In this project, you will apply unsupervised learning techniques to identify segments of the population that form the core customer base for a mail-order sales company in Germany. These segments can then be used to direct marketing campaigns towards audiences that will have the highest expected rate of returns. The data that you will use has been provided by our partners at Bertelsmann Arvato Analytics, and represents a real-life data science task.
This notebook will help you complete this task by providing a framework within which you will perform your analysis steps. In each step of the project, you will see some text describing the subtask that you will perform, followed by one or more code cells for you to complete your work. Feel free to add additional code and markdown cells as you go along so that you can explore everything in precise chunks. The code cells provided in the base template will outline only the major tasks, and will usually not be enough to cover all of the minor tasks that comprise it.
It should be noted that while there will be precise guidelines on how you should handle certain tasks in the project, there will also be places where an exact specification is not provided. There will be times in the project where you will need to make and justify your own decisions on how to treat the data. These are places where there may not be only one way to handle the data. In real-life tasks, there may be many valid ways to approach an analysis task. One of the most important things you can do is clearly document your approach so that other scientists can understand the decisions you've made.
At the end of most sections, there will be a Markdown cell labeled Discussion. In these cells, you will report your findings for the completed section, as well as document the decisions that you made in your approach to each subtask. Your project will be evaluated not just on the code used to complete the tasks outlined, but also your communication about your observations and conclusions at each stage.
# import libraries here; add more as necessary
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# magic word for producing visualizations in notebook
%matplotlib inline
pd.set_option('display.max_columns', 100)
pd.set_option('display.max_rows', 100)
import warnings
from collections import Counter
warnings.filterwarnings('ignore')
'''
Import note: The classroom currently uses sklearn version 0.19.
If you need to use an imputer, it is available in sklearn.preprocessing.Imputer,
instead of sklearn.impute as in newer versions of sklearn.
'''
'\nImport note: The classroom currently uses sklearn version 0.19.\nIf you need to use an imputer, it is available in sklearn.preprocessing.Imputer,\ninstead of sklearn.impute as in newer versions of sklearn.\n'
# Visualizations libraries
import matplotlib.ticker as mtick
import matplotlib.gridspec as grid_spec
from matplotlib.offsetbox import AnchoredText
from mpl_toolkits.axes_grid1 import make_axes_locatable
import plotly
import plotly.offline as pyo
import plotly.express as px
import plotly.graph_objs as go
pyo.init_notebook_mode()
import plotly.figure_factory as ff
import missingno as msno
# Machine Learning libraries
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
There are four files associated with this project (not including this one):
Udacity_AZDIAS_Subset.csv: Demographics data for the general population of Germany; 891211 persons (rows) x 85 features (columns).Udacity_CUSTOMERS_Subset.csv: Demographics data for customers of a mail-order company; 191652 persons (rows) x 85 features (columns).Data_Dictionary.md: Detailed information file about the features in the provided datasets.AZDIAS_Feature_Summary.csv: Summary of feature attributes for demographics data; 85 features (rows) x 4 columnsEach row of the demographics files represents a single person, but also includes information outside of individuals, including information about their household, building, and neighborhood. You will use this information to cluster the general population into groups with similar demographic properties. Then, you will see how the people in the customers dataset fit into those created clusters. The hope here is that certain clusters are over-represented in the customers data, as compared to the general population; those over-represented clusters will be assumed to be part of the core userbase. This information can then be used for further applications, such as targeting for a marketing campaign.
To start off with, load in the demographics data for the general population into a pandas DataFrame, and do the same for the feature attributes summary. Note for all of the .csv data files in this project: they're semicolon (;) delimited, so you'll need an additional argument in your read_csv() call to read in the data properly. Also, considering the size of the main dataset, it may take some time for it to load completely.
Once the dataset is loaded, it's recommended that you take a little bit of time just browsing the general structure of the dataset and feature summary file. You'll be getting deep into the innards of the cleaning in the first major step of the project, so gaining some general familiarity can help you get your bearings.
from pathlib import Path
import os
os.getcwd()
'/Users/yejiseoung/Dropbox/My Mac (Yejis-MacBook-Pro.local)/Documents/Projects/UdacityClusterProject'
path = Path('/Users/yejiseoung/Dropbox/My Mac (Yejis-MacBook-Pro.local)/Documents/Projects/UdacityClusterProject/Data')
# Load in the general demographics data.
azdias = pd.read_csv(path/'Udacity_AZDIAS_Subset.csv', delimiter=';')
# Load in the feature summary file.
feat_info = pd.read_csv(path/'AZDIAS_Feature_Summary.csv', delimiter=';')
feat_info
| attribute | information_level | type | missing_or_unknown | |
|---|---|---|---|---|
| 0 | AGER_TYP | person | categorical | [-1,0] |
| 1 | ALTERSKATEGORIE_GROB | person | ordinal | [-1,0,9] |
| 2 | ANREDE_KZ | person | categorical | [-1,0] |
| 3 | CJT_GESAMTTYP | person | categorical | [0] |
| 4 | FINANZ_MINIMALIST | person | ordinal | [-1] |
| 5 | FINANZ_SPARER | person | ordinal | [-1] |
| 6 | FINANZ_VORSORGER | person | ordinal | [-1] |
| 7 | FINANZ_ANLEGER | person | ordinal | [-1] |
| 8 | FINANZ_UNAUFFAELLIGER | person | ordinal | [-1] |
| 9 | FINANZ_HAUSBAUER | person | ordinal | [-1] |
| 10 | FINANZTYP | person | categorical | [-1] |
| 11 | GEBURTSJAHR | person | numeric | [0] |
| 12 | GFK_URLAUBERTYP | person | categorical | [] |
| 13 | GREEN_AVANTGARDE | person | categorical | [] |
| 14 | HEALTH_TYP | person | ordinal | [-1,0] |
| 15 | LP_LEBENSPHASE_FEIN | person | mixed | [0] |
| 16 | LP_LEBENSPHASE_GROB | person | mixed | [0] |
| 17 | LP_FAMILIE_FEIN | person | categorical | [0] |
| 18 | LP_FAMILIE_GROB | person | categorical | [0] |
| 19 | LP_STATUS_FEIN | person | categorical | [0] |
| 20 | LP_STATUS_GROB | person | categorical | [0] |
| 21 | NATIONALITAET_KZ | person | categorical | [-1,0] |
| 22 | PRAEGENDE_JUGENDJAHRE | person | mixed | [-1,0] |
| 23 | RETOURTYP_BK_S | person | ordinal | [0] |
| 24 | SEMIO_SOZ | person | ordinal | [-1,9] |
| 25 | SEMIO_FAM | person | ordinal | [-1,9] |
| 26 | SEMIO_REL | person | ordinal | [-1,9] |
| 27 | SEMIO_MAT | person | ordinal | [-1,9] |
| 28 | SEMIO_VERT | person | ordinal | [-1,9] |
| 29 | SEMIO_LUST | person | ordinal | [-1,9] |
| 30 | SEMIO_ERL | person | ordinal | [-1,9] |
| 31 | SEMIO_KULT | person | ordinal | [-1,9] |
| 32 | SEMIO_RAT | person | ordinal | [-1,9] |
| 33 | SEMIO_KRIT | person | ordinal | [-1,9] |
| 34 | SEMIO_DOM | person | ordinal | [-1,9] |
| 35 | SEMIO_KAEM | person | ordinal | [-1,9] |
| 36 | SEMIO_PFLICHT | person | ordinal | [-1,9] |
| 37 | SEMIO_TRADV | person | ordinal | [-1,9] |
| 38 | SHOPPER_TYP | person | categorical | [-1] |
| 39 | SOHO_KZ | person | categorical | [-1] |
| 40 | TITEL_KZ | person | categorical | [-1,0] |
| 41 | VERS_TYP | person | categorical | [-1] |
| 42 | ZABEOTYP | person | categorical | [-1,9] |
| 43 | ALTER_HH | household | interval | [0] |
| 44 | ANZ_PERSONEN | household | numeric | [] |
| 45 | ANZ_TITEL | household | numeric | [] |
| 46 | HH_EINKOMMEN_SCORE | household | ordinal | [-1,0] |
| 47 | KK_KUNDENTYP | household | categorical | [-1] |
| 48 | W_KEIT_KIND_HH | household | ordinal | [-1,0] |
| 49 | WOHNDAUER_2008 | household | ordinal | [-1,0] |
| 50 | ANZ_HAUSHALTE_AKTIV | building | numeric | [0] |
| 51 | ANZ_HH_TITEL | building | numeric | [] |
| 52 | GEBAEUDETYP | building | categorical | [-1,0] |
| 53 | KONSUMNAEHE | building | ordinal | [] |
| 54 | MIN_GEBAEUDEJAHR | building | numeric | [0] |
| 55 | OST_WEST_KZ | building | categorical | [-1] |
| 56 | WOHNLAGE | building | mixed | [-1] |
| 57 | CAMEO_DEUG_2015 | microcell_rr4 | categorical | [-1,X] |
| 58 | CAMEO_DEU_2015 | microcell_rr4 | categorical | [XX] |
| 59 | CAMEO_INTL_2015 | microcell_rr4 | mixed | [-1,XX] |
| 60 | KBA05_ANTG1 | microcell_rr3 | ordinal | [-1] |
| 61 | KBA05_ANTG2 | microcell_rr3 | ordinal | [-1] |
| 62 | KBA05_ANTG3 | microcell_rr3 | ordinal | [-1] |
| 63 | KBA05_ANTG4 | microcell_rr3 | ordinal | [-1] |
| 64 | KBA05_BAUMAX | microcell_rr3 | mixed | [-1,0] |
| 65 | KBA05_GBZ | microcell_rr3 | ordinal | [-1,0] |
| 66 | BALLRAUM | postcode | ordinal | [-1] |
| 67 | EWDICHTE | postcode | ordinal | [-1] |
| 68 | INNENSTADT | postcode | ordinal | [-1] |
| 69 | GEBAEUDETYP_RASTER | region_rr1 | ordinal | [] |
| 70 | KKK | region_rr1 | ordinal | [-1,0] |
| 71 | MOBI_REGIO | region_rr1 | ordinal | [] |
| 72 | ONLINE_AFFINITAET | region_rr1 | ordinal | [] |
| 73 | REGIOTYP | region_rr1 | ordinal | [-1,0] |
| 74 | KBA13_ANZAHL_PKW | macrocell_plz8 | numeric | [] |
| 75 | PLZ8_ANTG1 | macrocell_plz8 | ordinal | [-1] |
| 76 | PLZ8_ANTG2 | macrocell_plz8 | ordinal | [-1] |
| 77 | PLZ8_ANTG3 | macrocell_plz8 | ordinal | [-1] |
| 78 | PLZ8_ANTG4 | macrocell_plz8 | ordinal | [-1] |
| 79 | PLZ8_BAUMAX | macrocell_plz8 | mixed | [-1,0] |
| 80 | PLZ8_HHZ | macrocell_plz8 | ordinal | [-1] |
| 81 | PLZ8_GBZ | macrocell_plz8 | ordinal | [-1] |
| 82 | ARBEIT | community | ordinal | [-1,9] |
| 83 | ORTSGR_KLS9 | community | ordinal | [-1,0] |
| 84 | RELAT_AB | community | ordinal | [-1,9] |
# Check the structure of the data after it's loaded (e.g. print the number of
# rows and columns, print the first few rows).
azdias.head()
| AGER_TYP | ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GEBURTSJAHR | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_LEBENSPHASE_FEIN | LP_LEBENSPHASE_GROB | LP_FAMILIE_FEIN | LP_FAMILIE_GROB | LP_STATUS_FEIN | LP_STATUS_GROB | NATIONALITAET_KZ | PRAEGENDE_JUGENDJAHRE | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | TITEL_KZ | VERS_TYP | ZABEOTYP | ALTER_HH | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | KK_KUNDENTYP | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | GEBAEUDETYP | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | WOHNLAGE | CAMEO_DEUG_2015 | CAMEO_DEU_2015 | CAMEO_INTL_2015 | KBA05_ANTG1 | KBA05_ANTG2 | KBA05_ANTG3 | KBA05_ANTG4 | KBA05_BAUMAX | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_ANTG1 | PLZ8_ANTG2 | PLZ8_ANTG3 | PLZ8_ANTG4 | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | -1 | 2 | 1 | 2.0 | 3 | 4 | 3 | 5 | 5 | 3 | 4 | 0 | 10.0 | 0 | -1 | 15.0 | 4.0 | 2.0 | 2.0 | 1.0 | 1.0 | 0 | 0 | 5.0 | 2 | 6 | 7 | 5 | 1 | 5 | 3 | 3 | 4 | 7 | 6 | 6 | 5 | 3 | -1 | NaN | NaN | -1 | 3 | NaN | NaN | NaN | 2.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
| 1 | -1 | 1 | 2 | 5.0 | 1 | 5 | 2 | 5 | 4 | 5 | 1 | 1996 | 10.0 | 0 | 3 | 21.0 | 6.0 | 5.0 | 3.0 | 2.0 | 1.0 | 1 | 14 | 1.0 | 5 | 4 | 4 | 3 | 1 | 2 | 2 | 3 | 6 | 4 | 7 | 4 | 7 | 6 | 3 | 1.0 | 0.0 | 2 | 5 | 0.0 | 2.0 | 0.0 | 6.0 | NaN | 3.0 | 9.0 | 11.0 | 0.0 | 8.0 | 1.0 | 1992.0 | W | 4.0 | 8 | 8A | 51 | 0.0 | 0.0 | 0.0 | 2.0 | 5.0 | 1.0 | 6.0 | 3.0 | 8.0 | 3.0 | 2.0 | 1.0 | 3.0 | 3.0 | 963.0 | 2.0 | 3.0 | 2.0 | 1.0 | 1.0 | 5.0 | 4.0 | 3.0 | 5.0 | 4.0 |
| 2 | -1 | 3 | 2 | 3.0 | 1 | 4 | 1 | 2 | 3 | 5 | 1 | 1979 | 10.0 | 1 | 3 | 3.0 | 1.0 | 1.0 | 1.0 | 3.0 | 2.0 | 1 | 15 | 3.0 | 4 | 1 | 3 | 3 | 4 | 4 | 6 | 3 | 4 | 7 | 7 | 7 | 3 | 3 | 2 | 0.0 | 0.0 | 1 | 5 | 17.0 | 1.0 | 0.0 | 4.0 | NaN | 3.0 | 9.0 | 10.0 | 0.0 | 1.0 | 5.0 | 1992.0 | W | 2.0 | 4 | 4C | 24 | 1.0 | 3.0 | 1.0 | 0.0 | 0.0 | 3.0 | 2.0 | 4.0 | 4.0 | 4.0 | 2.0 | 3.0 | 2.0 | 2.0 | 712.0 | 3.0 | 3.0 | 1.0 | 0.0 | 1.0 | 4.0 | 4.0 | 3.0 | 5.0 | 2.0 |
| 3 | 2 | 4 | 2 | 2.0 | 4 | 2 | 5 | 2 | 1 | 2 | 6 | 1957 | 1.0 | 0 | 2 | 0.0 | 0.0 | 0.0 | 0.0 | 9.0 | 4.0 | 1 | 8 | 2.0 | 5 | 1 | 2 | 1 | 4 | 4 | 7 | 4 | 3 | 4 | 4 | 5 | 4 | 4 | 1 | 0.0 | 0.0 | 1 | 3 | 13.0 | 0.0 | 0.0 | 1.0 | NaN | NaN | 9.0 | 1.0 | 0.0 | 1.0 | 4.0 | 1997.0 | W | 7.0 | 2 | 2A | 12 | 4.0 | 1.0 | 0.0 | 0.0 | 1.0 | 4.0 | 4.0 | 2.0 | 6.0 | 4.0 | 0.0 | 4.0 | 1.0 | 0.0 | 596.0 | 2.0 | 2.0 | 2.0 | 0.0 | 1.0 | 3.0 | 4.0 | 2.0 | 3.0 | 3.0 |
| 4 | -1 | 3 | 1 | 5.0 | 4 | 3 | 4 | 1 | 3 | 2 | 5 | 1963 | 5.0 | 0 | 3 | 32.0 | 10.0 | 10.0 | 5.0 | 3.0 | 2.0 | 1 | 8 | 5.0 | 6 | 4 | 4 | 2 | 7 | 4 | 4 | 6 | 2 | 3 | 2 | 2 | 4 | 2 | 2 | 0.0 | 0.0 | 2 | 4 | 20.0 | 4.0 | 0.0 | 5.0 | 1.0 | 2.0 | 9.0 | 3.0 | 0.0 | 1.0 | 4.0 | 1992.0 | W | 3.0 | 6 | 6B | 43 | 1.0 | 4.0 | 1.0 | 0.0 | 0.0 | 3.0 | 2.0 | 5.0 | 1.0 | 5.0 | 3.0 | 3.0 | 5.0 | 5.0 | 435.0 | 2.0 | 4.0 | 2.0 | 1.0 | 2.0 | 3.0 | 3.0 | 4.0 | 6.0 | 5.0 |
azdias.shape
(891221, 85)
azdias.dtypes
AGER_TYP float64 ALTERSKATEGORIE_GROB float64 ANREDE_KZ int64 CJT_GESAMTTYP float64 FINANZ_MINIMALIST int64 FINANZ_SPARER int64 FINANZ_VORSORGER int64 FINANZ_ANLEGER int64 FINANZ_UNAUFFAELLIGER int64 FINANZ_HAUSBAUER int64 FINANZTYP int64 GEBURTSJAHR float64 GFK_URLAUBERTYP float64 GREEN_AVANTGARDE int64 HEALTH_TYP float64 LP_LEBENSPHASE_FEIN float64 LP_LEBENSPHASE_GROB float64 LP_FAMILIE_FEIN float64 LP_FAMILIE_GROB float64 LP_STATUS_FEIN float64 LP_STATUS_GROB float64 NATIONALITAET_KZ float64 PRAEGENDE_JUGENDJAHRE float64 RETOURTYP_BK_S float64 SEMIO_SOZ int64 SEMIO_FAM int64 SEMIO_REL int64 SEMIO_MAT int64 SEMIO_VERT int64 SEMIO_LUST int64 SEMIO_ERL int64 SEMIO_KULT int64 SEMIO_RAT int64 SEMIO_KRIT int64 SEMIO_DOM int64 SEMIO_KAEM int64 SEMIO_PFLICHT int64 SEMIO_TRADV int64 SHOPPER_TYP float64 SOHO_KZ float64 TITEL_KZ float64 VERS_TYP float64 ZABEOTYP int64 ALTER_HH float64 ANZ_PERSONEN float64 ANZ_TITEL float64 HH_EINKOMMEN_SCORE float64 KK_KUNDENTYP float64 W_KEIT_KIND_HH float64 WOHNDAUER_2008 float64 ANZ_HAUSHALTE_AKTIV float64 ANZ_HH_TITEL float64 GEBAEUDETYP float64 KONSUMNAEHE float64 MIN_GEBAEUDEJAHR float64 OST_WEST_KZ object WOHNLAGE float64 CAMEO_DEUG_2015 object CAMEO_DEU_2015 object CAMEO_INTL_2015 object KBA05_ANTG1 float64 KBA05_ANTG2 float64 KBA05_ANTG3 float64 KBA05_ANTG4 float64 KBA05_BAUMAX float64 KBA05_GBZ float64 BALLRAUM float64 EWDICHTE float64 INNENSTADT float64 GEBAEUDETYP_RASTER float64 KKK float64 MOBI_REGIO float64 ONLINE_AFFINITAET float64 REGIOTYP float64 KBA13_ANZAHL_PKW float64 PLZ8_ANTG1 float64 PLZ8_ANTG2 float64 PLZ8_ANTG3 float64 PLZ8_ANTG4 float64 PLZ8_BAUMAX float64 PLZ8_HHZ float64 PLZ8_GBZ float64 ARBEIT float64 ORTSGR_KLS9 float64 RELAT_AB float64 dtype: object
azdias.describe()
| AGER_TYP | ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GEBURTSJAHR | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_LEBENSPHASE_FEIN | LP_LEBENSPHASE_GROB | LP_FAMILIE_FEIN | LP_FAMILIE_GROB | LP_STATUS_FEIN | LP_STATUS_GROB | NATIONALITAET_KZ | PRAEGENDE_JUGENDJAHRE | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | TITEL_KZ | VERS_TYP | ZABEOTYP | ALTER_HH | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | KK_KUNDENTYP | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | GEBAEUDETYP | KONSUMNAEHE | MIN_GEBAEUDEJAHR | WOHNLAGE | KBA05_ANTG1 | KBA05_ANTG2 | KBA05_ANTG3 | KBA05_ANTG4 | KBA05_BAUMAX | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_ANTG1 | PLZ8_ANTG2 | PLZ8_ANTG3 | PLZ8_ANTG4 | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 205378.000000 | 888340.000000 | 891221.000000 | 886367.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 498903.000000 | 886367.000000 | 891221.000000 | 780025.000000 | 793589.000000 | 796649.000000 | 813429.000000 | 813429.000000 | 886367.000000 | 886367.000000 | 782906.000000 | 783057.000000 | 886367.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 891221.000000 | 780025.000000 | 817722.000000 | 2160.000000 | 780025.000000 | 891221.000000 | 580954.000000 | 817722.000000 | 817722.000000 | 872873.000000 | 306609.000000 | 743233.000000 | 817722.000000 | 791610.000000 | 794213.000000 | 798073.000000 | 817252.000000 | 798073.000000 | 798073.000000 | 757897.000000 | 757897.000000 | 757897.000000 | 757897.000000 | 414697.000000 | 757897.000000 | 797481.000000 | 797481.000000 | 797481.000000 | 798066.000000 | 733157.000000 | 757897.000000 | 886367.000000 | 733157.000000 | 785421.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 793846.000000 | 793947.000000 | 793846.000000 |
| mean | 1.743410 | 2.757217 | 1.522098 | 3.632838 | 3.074528 | 2.821039 | 3.401106 | 3.033328 | 2.874167 | 3.075121 | 3.790586 | 1967.102689 | 7.350304 | 0.196612 | 2.190129 | 16.332161 | 4.955185 | 3.922339 | 2.381976 | 4.791151 | 2.432575 | 1.168889 | 9.280709 | 3.419630 | 3.945860 | 4.272729 | 4.240609 | 4.001597 | 4.023709 | 4.359086 | 4.481405 | 4.025014 | 3.910139 | 4.763223 | 4.667550 | 4.445007 | 4.256076 | 3.661784 | 1.590134 | 0.008423 | 1.318519 | 1.511166 | 3.362438 | 15.291805 | 1.727637 | 0.004162 | 4.207243 | 3.410640 | 4.147141 | 7.908791 | 8.354924 | 0.040647 | 2.798641 | 3.018452 | 1993.277011 | 4.052836 | 1.494277 | 1.265584 | 0.624525 | 0.305927 | 2.539534 | 3.158580 | 4.153043 | 3.939172 | 4.549491 | 3.738306 | 2.723384 | 2.963540 | 2.698691 | 4.472086 | 619.701439 | 2.253330 | 2.801858 | 1.595426 | 0.699166 | 1.943913 | 3.612821 | 3.381087 | 3.166686 | 5.293389 | 3.071033 |
| std | 0.674312 | 1.009951 | 0.499512 | 1.595021 | 1.321055 | 1.464749 | 1.322134 | 1.529603 | 1.486731 | 1.353248 | 1.987876 | 17.795208 | 3.525723 | 0.397437 | 0.755213 | 12.242378 | 3.748974 | 3.941285 | 1.701527 | 3.425305 | 1.474315 | 0.475075 | 4.032107 | 1.417741 | 1.946564 | 1.915885 | 2.007373 | 1.857540 | 2.077746 | 2.022829 | 1.807552 | 1.903816 | 1.580306 | 1.830789 | 1.795712 | 1.852412 | 1.770137 | 1.707637 | 1.027972 | 0.091392 | 0.999504 | 0.499876 | 1.352704 | 3.800536 | 1.155849 | 0.068855 | 1.624057 | 1.628844 | 1.784211 | 1.923137 | 15.673731 | 0.324028 | 2.656713 | 1.550312 | 3.332739 | 1.949539 | 1.403961 | 1.245178 | 1.013443 | 0.638725 | 1.693151 | 1.329537 | 2.183710 | 1.718996 | 2.028919 | 0.923193 | 0.979867 | 1.428882 | 1.521524 | 1.836357 | 340.034318 | 0.972008 | 0.920309 | 0.986736 | 0.727137 | 1.459654 | 0.973967 | 1.111598 | 0.999072 | 2.303379 | 1.360532 |
| min | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1900.000000 | 1.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1.000000 | 1.000000 | 1985.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
| 25% | 1.000000 | 2.000000 | 1.000000 | 2.000000 | 2.000000 | 1.000000 | 3.000000 | 2.000000 | 2.000000 | 2.000000 | 2.000000 | 1955.000000 | 5.000000 | 0.000000 | 2.000000 | 6.000000 | 2.000000 | 1.000000 | 1.000000 | 2.000000 | 1.000000 | 1.000000 | 6.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 2.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 2.000000 | 1.000000 | 0.000000 | 1.000000 | 1.000000 | 3.000000 | 13.000000 | 1.000000 | 0.000000 | 3.000000 | 2.000000 | 3.000000 | 8.000000 | 2.000000 | 0.000000 | 1.000000 | 2.000000 | 1992.000000 | 3.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 1.000000 | 2.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 2.000000 | 2.000000 | 1.000000 | 3.000000 | 384.000000 | 1.000000 | 2.000000 | 1.000000 | 0.000000 | 1.000000 | 3.000000 | 3.000000 | 3.000000 | 4.000000 | 2.000000 |
| 50% | 2.000000 | 3.000000 | 2.000000 | 4.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 3.000000 | 4.000000 | 1968.000000 | 8.000000 | 0.000000 | 2.000000 | 13.000000 | 3.000000 | 1.000000 | 1.000000 | 4.000000 | 2.000000 | 1.000000 | 9.000000 | 3.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 5.000000 | 4.000000 | 4.000000 | 4.000000 | 5.000000 | 5.000000 | 5.000000 | 4.000000 | 3.000000 | 2.000000 | 0.000000 | 1.000000 | 2.000000 | 3.000000 | 16.000000 | 1.000000 | 0.000000 | 5.000000 | 3.000000 | 4.000000 | 9.000000 | 4.000000 | 0.000000 | 1.000000 | 3.000000 | 1992.000000 | 3.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 3.000000 | 5.000000 | 4.000000 | 5.000000 | 4.000000 | 3.000000 | 3.000000 | 3.000000 | 5.000000 | 549.000000 | 2.000000 | 3.000000 | 2.000000 | 1.000000 | 1.000000 | 4.000000 | 3.000000 | 3.000000 | 5.000000 | 3.000000 |
| 75% | 2.000000 | 4.000000 | 2.000000 | 5.000000 | 4.000000 | 4.000000 | 5.000000 | 5.000000 | 4.000000 | 4.000000 | 6.000000 | 1981.000000 | 10.000000 | 0.000000 | 3.000000 | 28.000000 | 8.000000 | 8.000000 | 4.000000 | 9.000000 | 4.000000 | 1.000000 | 14.000000 | 5.000000 | 6.000000 | 6.000000 | 6.000000 | 5.000000 | 6.000000 | 6.000000 | 6.000000 | 5.000000 | 5.000000 | 6.000000 | 6.000000 | 6.000000 | 6.000000 | 5.000000 | 2.000000 | 0.000000 | 1.000000 | 2.000000 | 4.000000 | 18.000000 | 2.000000 | 0.000000 | 6.000000 | 5.000000 | 6.000000 | 9.000000 | 10.000000 | 0.000000 | 3.000000 | 4.000000 | 1993.000000 | 5.000000 | 3.000000 | 2.000000 | 1.000000 | 0.000000 | 4.000000 | 4.000000 | 6.000000 | 6.000000 | 6.000000 | 4.000000 | 3.000000 | 4.000000 | 4.000000 | 6.000000 | 778.000000 | 3.000000 | 3.000000 | 2.000000 | 1.000000 | 3.000000 | 4.000000 | 4.000000 | 4.000000 | 7.000000 | 4.000000 |
| max | 3.000000 | 4.000000 | 2.000000 | 6.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 6.000000 | 2017.000000 | 12.000000 | 1.000000 | 3.000000 | 40.000000 | 12.000000 | 11.000000 | 5.000000 | 10.000000 | 5.000000 | 3.000000 | 15.000000 | 5.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 3.000000 | 1.000000 | 5.000000 | 2.000000 | 6.000000 | 21.000000 | 45.000000 | 6.000000 | 6.000000 | 6.000000 | 6.000000 | 9.000000 | 595.000000 | 23.000000 | 8.000000 | 7.000000 | 2016.000000 | 8.000000 | 4.000000 | 4.000000 | 3.000000 | 2.000000 | 5.000000 | 5.000000 | 7.000000 | 6.000000 | 8.000000 | 5.000000 | 4.000000 | 6.000000 | 5.000000 | 7.000000 | 2300.000000 | 4.000000 | 4.000000 | 3.000000 | 2.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 9.000000 | 5.000000 |
Tip: Add additional cells to keep everything in reasonably-sized chunks! Keyboard shortcut
esc --> a(press escape to enter command mode, then press the 'A' key) adds a new cell before the active cell, andesc --> badds a new cell after the active cell. If you need to convert an active cell to a markdown cell, useesc --> mand to convert to a code cell, useesc --> y.
The feature summary file contains a summary of properties for each demographics data column. You will use this file to help you make cleaning decisions during this stage of the project. First of all, you should assess the demographics data in terms of missing data. Pay attention to the following points as you perform your analysis, and take notes on what you observe. Make sure that you fill in the Discussion cell with your findings and decisions at the end of each step that has one!
The fourth column of the feature attributes summary (loaded in above as feat_info) documents the codes from the data dictionary that indicate missing or unknown data. While the file encodes this as a list (e.g. [-1,0]), this will get read in as a string object. You'll need to do a little bit of parsing to make use of it to identify and clean the data. Convert data that matches a 'missing' or 'unknown' value code into a numpy NaN value. You might want to see how much data takes on a 'missing' or 'unknown' code, and how much data is naturally missing, as a point of interest.
As one more reminder, you are encouraged to add additional cells to break up your analysis into manageable chunks.
As we can see the cell below, there are a lot of columns that have missing values. Some columns have -1 meaning of missing values, 0 meaning of "unknown" values. So I would like to convert -1 values to np.nan values. By doing so, I want to differentiate missing values to unknown values.
feat_info
| attribute | information_level | type | missing_or_unknown | |
|---|---|---|---|---|
| 0 | AGER_TYP | person | categorical | [-1,0] |
| 1 | ALTERSKATEGORIE_GROB | person | ordinal | [-1,0,9] |
| 2 | ANREDE_KZ | person | categorical | [-1,0] |
| 3 | CJT_GESAMTTYP | person | categorical | [0] |
| 4 | FINANZ_MINIMALIST | person | ordinal | [-1] |
| 5 | FINANZ_SPARER | person | ordinal | [-1] |
| 6 | FINANZ_VORSORGER | person | ordinal | [-1] |
| 7 | FINANZ_ANLEGER | person | ordinal | [-1] |
| 8 | FINANZ_UNAUFFAELLIGER | person | ordinal | [-1] |
| 9 | FINANZ_HAUSBAUER | person | ordinal | [-1] |
| 10 | FINANZTYP | person | categorical | [-1] |
| 11 | GEBURTSJAHR | person | numeric | [0] |
| 12 | GFK_URLAUBERTYP | person | categorical | [] |
| 13 | GREEN_AVANTGARDE | person | categorical | [] |
| 14 | HEALTH_TYP | person | ordinal | [-1,0] |
| 15 | LP_LEBENSPHASE_FEIN | person | mixed | [0] |
| 16 | LP_LEBENSPHASE_GROB | person | mixed | [0] |
| 17 | LP_FAMILIE_FEIN | person | categorical | [0] |
| 18 | LP_FAMILIE_GROB | person | categorical | [0] |
| 19 | LP_STATUS_FEIN | person | categorical | [0] |
| 20 | LP_STATUS_GROB | person | categorical | [0] |
| 21 | NATIONALITAET_KZ | person | categorical | [-1,0] |
| 22 | PRAEGENDE_JUGENDJAHRE | person | mixed | [-1,0] |
| 23 | RETOURTYP_BK_S | person | ordinal | [0] |
| 24 | SEMIO_SOZ | person | ordinal | [-1,9] |
| 25 | SEMIO_FAM | person | ordinal | [-1,9] |
| 26 | SEMIO_REL | person | ordinal | [-1,9] |
| 27 | SEMIO_MAT | person | ordinal | [-1,9] |
| 28 | SEMIO_VERT | person | ordinal | [-1,9] |
| 29 | SEMIO_LUST | person | ordinal | [-1,9] |
| 30 | SEMIO_ERL | person | ordinal | [-1,9] |
| 31 | SEMIO_KULT | person | ordinal | [-1,9] |
| 32 | SEMIO_RAT | person | ordinal | [-1,9] |
| 33 | SEMIO_KRIT | person | ordinal | [-1,9] |
| 34 | SEMIO_DOM | person | ordinal | [-1,9] |
| 35 | SEMIO_KAEM | person | ordinal | [-1,9] |
| 36 | SEMIO_PFLICHT | person | ordinal | [-1,9] |
| 37 | SEMIO_TRADV | person | ordinal | [-1,9] |
| 38 | SHOPPER_TYP | person | categorical | [-1] |
| 39 | SOHO_KZ | person | categorical | [-1] |
| 40 | TITEL_KZ | person | categorical | [-1,0] |
| 41 | VERS_TYP | person | categorical | [-1] |
| 42 | ZABEOTYP | person | categorical | [-1,9] |
| 43 | ALTER_HH | household | interval | [0] |
| 44 | ANZ_PERSONEN | household | numeric | [] |
| 45 | ANZ_TITEL | household | numeric | [] |
| 46 | HH_EINKOMMEN_SCORE | household | ordinal | [-1,0] |
| 47 | KK_KUNDENTYP | household | categorical | [-1] |
| 48 | W_KEIT_KIND_HH | household | ordinal | [-1,0] |
| 49 | WOHNDAUER_2008 | household | ordinal | [-1,0] |
| 50 | ANZ_HAUSHALTE_AKTIV | building | numeric | [0] |
| 51 | ANZ_HH_TITEL | building | numeric | [] |
| 52 | GEBAEUDETYP | building | categorical | [-1,0] |
| 53 | KONSUMNAEHE | building | ordinal | [] |
| 54 | MIN_GEBAEUDEJAHR | building | numeric | [0] |
| 55 | OST_WEST_KZ | building | categorical | [-1] |
| 56 | WOHNLAGE | building | mixed | [-1] |
| 57 | CAMEO_DEUG_2015 | microcell_rr4 | categorical | [-1,X] |
| 58 | CAMEO_DEU_2015 | microcell_rr4 | categorical | [XX] |
| 59 | CAMEO_INTL_2015 | microcell_rr4 | mixed | [-1,XX] |
| 60 | KBA05_ANTG1 | microcell_rr3 | ordinal | [-1] |
| 61 | KBA05_ANTG2 | microcell_rr3 | ordinal | [-1] |
| 62 | KBA05_ANTG3 | microcell_rr3 | ordinal | [-1] |
| 63 | KBA05_ANTG4 | microcell_rr3 | ordinal | [-1] |
| 64 | KBA05_BAUMAX | microcell_rr3 | mixed | [-1,0] |
| 65 | KBA05_GBZ | microcell_rr3 | ordinal | [-1,0] |
| 66 | BALLRAUM | postcode | ordinal | [-1] |
| 67 | EWDICHTE | postcode | ordinal | [-1] |
| 68 | INNENSTADT | postcode | ordinal | [-1] |
| 69 | GEBAEUDETYP_RASTER | region_rr1 | ordinal | [] |
| 70 | KKK | region_rr1 | ordinal | [-1,0] |
| 71 | MOBI_REGIO | region_rr1 | ordinal | [] |
| 72 | ONLINE_AFFINITAET | region_rr1 | ordinal | [] |
| 73 | REGIOTYP | region_rr1 | ordinal | [-1,0] |
| 74 | KBA13_ANZAHL_PKW | macrocell_plz8 | numeric | [] |
| 75 | PLZ8_ANTG1 | macrocell_plz8 | ordinal | [-1] |
| 76 | PLZ8_ANTG2 | macrocell_plz8 | ordinal | [-1] |
| 77 | PLZ8_ANTG3 | macrocell_plz8 | ordinal | [-1] |
| 78 | PLZ8_ANTG4 | macrocell_plz8 | ordinal | [-1] |
| 79 | PLZ8_BAUMAX | macrocell_plz8 | mixed | [-1,0] |
| 80 | PLZ8_HHZ | macrocell_plz8 | ordinal | [-1] |
| 81 | PLZ8_GBZ | macrocell_plz8 | ordinal | [-1] |
| 82 | ARBEIT | community | ordinal | [-1,9] |
| 83 | ORTSGR_KLS9 | community | ordinal | [-1,0] |
| 84 | RELAT_AB | community | ordinal | [-1,9] |
feat_info['missing_or_unknown'].unique()
array(['[-1,0]', '[-1,0,9]', '[0]', '[-1]', '[]', '[-1,9]', '[-1,X]',
'[XX]', '[-1,XX]'], dtype=object)
feat_info.groupby(['missing_or_unknown'])['attribute'].count()
missing_or_unknown [-1,0,9] 1 [-1,0] 16 [-1,9] 17 [-1,XX] 1 [-1,X] 1 [-1] 26 [0] 12 [XX] 1 [] 10 Name: attribute, dtype: int64
# Create lists of features name depending on the missing value info
m0 = []
m1 = []
m2 = []
m3 = []
m4 = []
m5 = []
m6 = []
m7 = []
m8 = []
for i in range(feat_info.shape[0]):
if feat_info['missing_or_unknown'][i] == '[]':
m0.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[0]':
m1.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1]':
m2.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1,0]':
m3.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1,9]':
m4.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1,X]':
m5.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1,XX]':
m6.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[XX]':
m7.append(feat_info['attribute'][i])
elif feat_info['missing_or_unknown'][i] == '[-1,0,9]':
m8.append(feat_info['attribute'][i])
# create loops for converting missing values to np.nan depending on missing values info
for col in m1:
azdias[col] = azdias[col].replace(0, np.nan)
for col in m2:
azdias[col] = azdias[col].replace(-1, np.nan)
for col in m3:
azdias[col] = azdias[col].replace(-1, np.nan)
azdias[col] = azdias[col].replace(0, np.nan)
for col in m4:
azdias[col] = azdias[col].replace(-1, np.nan)
azdias[col] = azdias[col].replace(9, np.nan)
for col in m5:
azdias[col] = azdias[col].replace(-1, np.nan)
azdias[col] = azdias[col].replace('X', np.nan)
for col in m6:
azdias[col] = azdias[col].replace(-1, np.nan)
azdias[col] = azdias[col].replace('XX', np.nan)
for col in m7:
azdias[col] = azdias[col].replace('XX', np.nan)
for col in m8:
azdias[col] = azdias[col].replace(-1, np.nan)
azdias[col] = azdias[col].replace(0, np.nan)
azdias[col] = azdias[col].replace(9, np.nan)
How much missing data is present in each column? There are a few columns that are outliers in terms of the proportion of values that are missing. You will want to use matplotlib's hist() function to visualize the distribution of missing value counts to find these columns. Identify and document these columns. While some of these columns might have justifications for keeping or re-encoding the data, for this project you should just remove them from the dataframe. (Feel free to make remarks about these outlier columns in the discussion, however!)
For the remaining features, are there any patterns in which columns have, or share, missing data?
missing_df = (azdias.isnull().sum()/len(azdias)).sort_values(ascending=True)
fig, ax = plt.subplots(figsize=(20, 20))
missing_df.plot(kind='barh', color='#17869E')
plt.xlabel('The percentage of missing values in the variable', fontsize=15);
# Observation
plt.text(0, 90, "The missing values in the dataset", fontsize=20, fontweight='bold', fontfamily='serif')
plt.text(0, 88, "- We can see there are 6 columns that have more than 30% of missing values in the dataset.",
fontsize=15, fontweight='light', fontfamily='serif')
plt.text(0, 86, "- We need to drop those columns and keep the rest of the features to analyze the data.",
fontsize=15, fontweight='light', fontfamily='serif');
# Ax spines
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(True)
ax.spines['left'].set_visible(True)
ax.spines['right'].set_visible(False)
ax.set_axisbelow(True)
ax.xaxis.grid(color='lightgray', linestyle='-');
(azdias.isnull().sum()/len(azdias)).sort_values(ascending=False)[:6]
TITEL_KZ 0.997576 AGER_TYP 0.769554 KK_KUNDENTYP 0.655967 KBA05_BAUMAX 0.534687 GEBURTSJAHR 0.440203 ALTER_HH 0.348137 dtype: float64
drop_cols = ['TITEL_KZ', 'AGER_TYP', 'KK_KUNDENTYP', 'KBA05_BAUMAX', 'GEBURTSJAHR', 'ALTER_HH']
azdias = azdias.drop(drop_cols, axis=1)
We can see there are 6 columns that have more than 30% of missing values in the dataset. We need to drop those columns and keep the rest of the features to analyze the data.
Now, you'll perform a similar assessment for the rows of the dataset. How much data is missing in each row? As with the columns, you should see some groups of points that have a very different numbers of missing values. Divide the data into two subsets: one for data points that are above some threshold for missing values, and a second subset for points below that threshold.
In order to know what to do with the outlier rows, we should see if the distribution of data values on columns that are not missing data (or are missing very little data) are similar or different between the two groups. Select at least five of these columns and compare the distribution of values.
countplot() function to create a bar chart of code frequencies and matplotlib's subplot() function to put bar charts for the two subplots side by side.Depending on what you observe in your comparison, this will have implications on how you approach your conclusions later in the analysis. If the distributions of non-missing features look similar between the data with many missing values and the data with few or no missing values, then we could argue that simply dropping those points from the analysis won't present a major issue. On the other hand, if the data with many missing values looks very different from the data with few or no missing values, then we should make a note on those data as special. We'll revisit these data later on. Either way, you should continue your analysis for now using just the subset of the data with few or no missing values.
azdias.isnull().sum(axis=1).sort_values(ascending=False)
732775 49
643174 49
472919 48
345274 47
299868 47
..
349047 0
349048 0
349049 0
349050 0
891220 0
Length: 891221, dtype: int64
# How much data is missing in each row of the dataset?
missing_rows = (azdias.isnull().sum(axis=1)).sort_values(ascending=False)
fig, ax = plt.subplots(figsize=(15, 10))
sns.countplot(missing_rows, color='#17869E')
ax.set_xlabel('The number of missing values in the rows', fontsize=12)
ax.annotate("The majority of rows do not have missing values",
xy=(10.5, 160000), fontsize=12, fontweight='bold',
va='center', ha='center',
color='#4a4a4a',
bbox=dict(boxstyle='round', pad=0.4, facecolor='#efe8d1', linewidth=0))
# Set up ax spines
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(True)
ax.spines['left'].set_visible(True)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_color('lightgray')
ax.spines['bottom'].set_color('lightgray')
# Grid
ax.set_axisbelow(True)
ax.yaxis.grid(color='lightgray', linestyle='-')
plt.show()
# Write code to divide the data into two subsets based on the number of missing
# values in each row.
MissingBelow = azdias[azdias.isnull().sum(axis=1)<=30]
MissingMore = azdias[azdias.isnull().sum(axis=1)>30]
# See what columns have no missing values
(azdias.isnull().sum()).sort_values(ascending=True)[:26]
ZABEOTYP 0 SEMIO_REL 0 SEMIO_MAT 0 SEMIO_VERT 0 SEMIO_LUST 0 SEMIO_ERL 0 SEMIO_KULT 0 SEMIO_RAT 0 SEMIO_KRIT 0 SEMIO_DOM 0 SEMIO_KAEM 0 GREEN_AVANTGARDE 0 SEMIO_PFLICHT 0 FINANZTYP 0 FINANZ_HAUSBAUER 0 FINANZ_UNAUFFAELLIGER 0 FINANZ_ANLEGER 0 FINANZ_VORSORGER 0 FINANZ_SPARER 0 FINANZ_MINIMALIST 0 SEMIO_TRADV 0 ANREDE_KZ 0 SEMIO_SOZ 0 SEMIO_FAM 0 ALTERSKATEGORIE_GROB 2881 LP_STATUS_GROB 4854 dtype: int64
# Compare the distribution of values for at least five columns where there are
# no or few missing values, between the two subsets.
NoMissingCols5 = ['ZABEOTYP', 'SEMIO_TRADV', 'FINANZ_VORSORGER', 'ANREDE_KZ', 'GREEN_AVANTGARDE']
We can see that the variables with less missing rows and those with more missing rows show different distributions.
def Create_CountPlots(xVar):
""" Function to create count plots to compare two groups
Args:
xVar: a list for variables
"""
fig = plt.figure(10, figsize=(12,4))
ax1 = fig.add_subplot(121)
ax1.set_title('Less Missing Rows')
sns.countplot(MissingBelow[xVar], color='#17869E', label='below30')
ax2 = fig.add_subplot(122)
ax2.set_title('More Missing Rows')
sns.countplot(MissingMore[xVar], color='#9b1b30', alpha=0.4, label='more30')
fig.suptitle(xVar)
plt.show()
for i in range(5):
Create_CountPlots(NoMissingCols5[i])
# copy the dataset and create dataset which drops missing rows that have more than 30% of it.
copy = azdias.copy()
copy.drop(MissingMore.index, axis=0, inplace=True)
Even though I dropped rows which have more than 30% missing values, the distributions of both all dataset and dropped dataset are pretty similar, so I would like to drop 30% missing rows.
def Create_CountPlots(xVar):
""" Function to create count plots to compare two groups
Args:
xVar: a list for variables
"""
fig = plt.figure(10, figsize=(12,4))
ax1 = fig.add_subplot(121)
ax1.set_title('Dataset which dropped missing rows')
sns.countplot(copy[xVar], color='#17869E', label='dropped missing rows')
ax2 = fig.add_subplot(122)
ax2.set_title('All Dataset')
sns.countplot(azdias[xVar], color='#9b1b30', alpha=0.4, label='all')
fig.suptitle(xVar)
plt.show()
for i in range(5):
Create_CountPlots(NoMissingCols5[i])
# full dataset shape
azdias.shape
(891221, 79)
azdias.drop(MissingMore.index, axis=0, inplace=True)
# dataset shape after drop the missing rows (>30%)
azdias.shape
(798067, 79)
Given the comparison between the fewer missing rows (<30%) and more missing rows (>30%) variable, they show the different distributions in 4 variables ('ZABEOTYP', 'SEMIO_TRADV', 'FINANZ_VORSORGER', 'GREEN_AVANTGARDE'). After that, I created the comparison plots (the dataset which were dropped the more missing rows (>30%) vs. full dataset), and 'SEMIO_TRADV', 'FINANZ_VORSORGER' show differences between these datasets but others look similar. So I decided to drop the rows which have more than 30% missing values for further analysis.
Checking for missing data isn't the only way in which you can prepare a dataset for analysis. Since the unsupervised learning techniques to be used will only work on data that is encoded numerically, you need to make a few encoding changes or additional assumptions to be able to make progress. In addition, while almost all of the values in the dataset are encoded using numbers, not all of them represent numeric values. Check the third column of the feature summary (feat_info) for a summary of types of measurement.
In the first two parts of this sub-step, you will perform an investigation of the categorical and mixed-type features and make a decision on each of them, whether you will keep, drop, or re-encode each. Then, in the last part, you will create a new data frame with only the selected and engineered columns.
Data wrangling is often the trickiest part of the data analysis process, and there's a lot of it to be done here. But stick with it: once you're done with this step, you'll be ready to get to the machine learning parts of the project!
feat_info.groupby(['type'])['attribute'].count()
type categorical 21 interval 1 mixed 7 numeric 7 ordinal 49 Name: attribute, dtype: int64
cat_feats = []
nch_feats = []
mix_feats = []
for i in range(feat_info.shape[0]):
if feat_info['type'][i] == 'categorical':
cat_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'ordinal':
nch_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'mixed':
mix_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'interval':
nch_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'numeric':
nch_feats.append(feat_info['attribute'][i])
# We have 85 features in dataset
len(cat_feats) + len(nch_feats) + len(mix_feats)
85
# How many features are there of each data type?
print("categorical features: {}\nmix features: {}\nnumerical, ordinal and interval: {}".format(len(cat_feats), len(mix_feats), len(nch_feats)))
categorical features: 21 mix features: 7 numerical, ordinal and interval: 57
3 categorical features and 1 mix feature were already dropped because they had a lot of missing values.
For categorical data, you would ordinarily need to encode the levels as dummy variables. Depending on the number of categories, perform one of the following:
Assess categorical variables: which are binary, which are multi-level, and which one needs to be re-encoded?
# See each features' unique values (18 features)
for cat in cat_feats:
if cat not in azdias.columns: continue
print(cat, azdias[cat].unique())
ANREDE_KZ [2 1] CJT_GESAMTTYP [ 5. 3. 2. 4. 1. 6. nan] FINANZTYP [1 6 5 2 4 3] GFK_URLAUBERTYP [10. 1. 5. 12. 9. 3. 8. 11. 4. 2. 7. 6. nan] GREEN_AVANTGARDE [0 1] LP_FAMILIE_FEIN [ 5. 1. nan 10. 2. 7. 11. 8. 4. 6. 9. 3.] LP_FAMILIE_GROB [ 3. 1. nan 5. 2. 4.] LP_STATUS_FEIN [ 2. 3. 9. 4. 1. 10. 5. 8. 6. 7. nan] LP_STATUS_GROB [ 1. 2. 4. 5. 3. nan] NATIONALITAET_KZ [ 1. 3. 2. nan] SHOPPER_TYP [ 3. 2. 1. 0. nan] SOHO_KZ [1. 0.] VERS_TYP [ 2. 1. nan] ZABEOTYP [5 3 4 1 6 2] GEBAEUDETYP [8. 1. 3. 2. 6. 4. 5.] OST_WEST_KZ ['W' 'O'] CAMEO_DEUG_2015 ['8' '4' '2' '6' '1' '9' '5' '7' nan '3'] CAMEO_DEU_2015 ['8A' '4C' '2A' '6B' '8C' '4A' '2D' '1A' '1E' '9D' '5C' '8B' '7A' '5D' '9E' nan '9B' '1B' '3D' '4E' '4B' '3C' '5A' '7B' '9A' '6D' '6E' '2C' '7C' '9C' '7D' '5E' '1D' '8D' '6C' '6A' '5B' '4D' '3A' '2B' '7E' '3B' '6F' '5F' '1C']
As we can see above, 'OST_WEST_KZ' has non-numeric values (W: west, O: east). So I will re-encode the values as 1, 2.
# re-encode OST_WEST_KZ values as 1,2
OST = {'W':2, 'O':1}
azdias['OST_WEST_KZ'] = azdias['OST_WEST_KZ'].map(OST)
azdias['OST_WEST_KZ'].unique()
array([2, 1])
# create a list of categorical features which have more than 3 levels (multi-level)
mul_feats = []
for cat in cat_feats:
if cat not in azdias.columns: continue
if azdias[cat].nunique() >= 3:
mul_feats.append(cat)
# there are 13 features with multi levels of categories
mul_feats
['CJT_GESAMTTYP', 'FINANZTYP', 'GFK_URLAUBERTYP', 'LP_FAMILIE_FEIN', 'LP_FAMILIE_GROB', 'LP_STATUS_FEIN', 'LP_STATUS_GROB', 'NATIONALITAET_KZ', 'SHOPPER_TYP', 'ZABEOTYP', 'GEBAEUDETYP', 'CAMEO_DEUG_2015', 'CAMEO_DEU_2015']
# see each feature that have more than 3 levels of category
for cat in mul_feats:
print(cat, '\n', azdias[cat].value_counts(),'\n\n')
CJT_GESAMTTYP 4.0 198296 3.0 147220 2.0 141269 5.0 111114 6.0 102108 1.0 93311 Name: CJT_GESAMTTYP, dtype: int64 FINANZTYP 6 289061 1 197172 5 106333 2 104774 4 55924 3 44803 Name: FINANZTYP, dtype: int64 GFK_URLAUBERTYP 12.0 130261 10.0 102831 8.0 83030 11.0 75103 5.0 70501 4.0 60422 9.0 57132 3.0 53101 1.0 50659 2.0 43858 7.0 40681 6.0 25739 Name: GFK_URLAUBERTYP, dtype: int64 LP_FAMILIE_FEIN 1.0 402556 10.0 128974 2.0 98555 11.0 48746 8.0 21780 7.0 19575 4.0 11574 5.0 11167 9.0 10452 6.0 8526 3.0 4688 Name: LP_FAMILIE_FEIN, dtype: int64 LP_FAMILIE_GROB 1.0 402556 5.0 188172 2.0 98555 4.0 49881 3.0 27429 Name: LP_FAMILIE_GROB, dtype: int64 LP_STATUS_FEIN 1.0 206853 9.0 136353 10.0 111574 2.0 111118 4.0 73973 3.0 68918 6.0 28896 5.0 27592 8.0 18837 7.0 9204 Name: LP_STATUS_FEIN, dtype: int64 LP_STATUS_GROB 1.0 317971 2.0 170483 4.0 155190 5.0 111574 3.0 38100 Name: LP_STATUS_GROB, dtype: int64 NATIONALITAET_KZ 1.0 667928 2.0 63651 3.0 32565 Name: NATIONALITAET_KZ, dtype: int64 SHOPPER_TYP 1.0 247414 2.0 205934 3.0 180865 0.0 127128 Name: SHOPPER_TYP, dtype: int64 ZABEOTYP 3 282243 4 207532 1 123458 5 80963 6 70866 2 33005 Name: ZABEOTYP, dtype: int64 GEBAEUDETYP 1.0 460463 3.0 178667 8.0 152474 2.0 4934 4.0 900 6.0 628 5.0 1 Name: GEBAEUDETYP, dtype: int64 CAMEO_DEUG_2015 8 134441 9 108177 6 105874 4 103911 3 86778 2 83230 7 77933 5 55310 1 36212 Name: CAMEO_DEUG_2015, dtype: int64 CAMEO_DEU_2015 6B 56672 8A 52438 4C 47819 2D 35074 3C 34769 7A 34399 3D 34306 8B 33434 4A 33154 8C 30993 9D 28593 9B 27676 9C 24987 7B 24503 9A 20542 2C 19422 8D 17576 6E 16107 2B 15485 5D 14943 6C 14820 2A 13249 5A 12214 1D 11909 1A 10850 3A 10543 5B 10354 5C 9935 7C 9065 4B 9047 4D 8570 3B 7160 6A 6810 9E 6379 6D 6073 6F 5392 7D 5333 4E 5321 1E 5065 7E 4633 1C 4317 5F 4283 1B 4071 5E 3581 Name: CAMEO_DEU_2015, dtype: int64
len(azdias.columns)
79
# drop 3 multi-levels of categorical variables
drop_mul = ['LP_FAMILIE_FEIN', 'LP_STATUS_FEIN', 'CAMEO_DEU_2015']
azdias.drop(drop_mul, axis=1, inplace=True)
len(azdias.columns)
76
I keep numerical, ordinal and interval's 57 features without any re-encoding. I decided to drop 3 multi-categorical variables because there are similar columns of them and they could be redundant. For example, 'LP_FAMILIE_FEIN' shows family type and fine scale and 'LP_FAMILIE_GROB' shows family type, rough scale. These are similar information, so I decided to keep fewer levels of categorical variables, which is LP_FAMILIE_GROB.
There are a handful of features that are marked as "mixed" in the feature summary that require special treatment in order to be included in the analysis. There are two in particular that deserve attention; the handling of the rest are up to your own choices:
Be sure to check Data_Dictionary.md for the details needed to finish these tasks.
mix_feats
['LP_LEBENSPHASE_FEIN', 'LP_LEBENSPHASE_GROB', 'PRAEGENDE_JUGENDJAHRE', 'WOHNLAGE', 'CAMEO_INTL_2015', 'KBA05_BAUMAX', 'PLZ8_BAUMAX']
# there are 6 mix features
for mix in mix_feats:
if mix not in azdias.columns: continue
print(mix, azdias[mix].unique())
LP_LEBENSPHASE_FEIN [21. 3. nan 32. 8. 2. 5. 10. 4. 6. 23. 12. 20. 1. 11. 25. 13. 18. 31. 38. 35. 30. 7. 22. 14. 29. 24. 28. 37. 26. 39. 27. 36. 9. 34. 33. 15. 40. 16. 19. 17.] LP_LEBENSPHASE_GROB [ 6. 1. nan 10. 2. 3. 5. 7. 12. 11. 9. 4. 8.] PRAEGENDE_JUGENDJAHRE [14. 15. 8. 3. 10. 11. 5. 9. 6. 4. nan 2. 1. 12. 13. 7.] WOHNLAGE [4. 2. 7. 3. 5. 1. 8. 0.] CAMEO_INTL_2015 ['51' '24' '12' '43' '54' '22' '14' '13' '15' '33' '41' '34' '55' nan '25' '23' '31' '52' '35' '45' '44' '32'] PLZ8_BAUMAX [ 1. 2. nan 4. 5. 3.]
Even though LP_LEBENSPHASE_FEIN's dtype is float64, the data dictionary shows LP_LEBENSPHASE_FEIN is a categorical variable. Also, LP_LEBENSPHASE_FEIN and LP_LEBENSPHASE_GROB have similar information in terms of life stage, so I would like to keep fewer categorical levels which is LP_LEBENSPHASE_GROB.
Also, LP_LEBENSPHASE_GROB dtype is float64 because it has Null values, so I cannot change LP_LEBENSPHASE_GROB's dtype as int64 like other categorical variables.
# drop a column because it has redundant info
azdias.drop(['LP_LEBENSPHASE_FEIN'], axis=1, inplace=True)
WOHNLAGE is a categorical variable and WOHNLAGE's dtype is float64, but I will change it to int64 like other categorical variables.
azdias['WOHNLAGE'] = azdias['WOHNLAGE'].astype('int64')
azdias['WOHNLAGE'].value_counts()
3 249719 7 169317 4 135973 2 100376 5 74346 1 43917 8 17472 0 6947 Name: WOHNLAGE, dtype: int64
Investigate "PRAEGENDE_JUGENDJAHRE" and engineer two new variables.
Dominating movement of person's youth (avantgarde vs. mainstream; east vs. west)
copy = azdias.copy()
# create a column for mainstream with value 0, 1
# if it has mainstream, then it will be encoded 1
mainstream = [1.0, 3.0, 5.0, 8.0, 10., 12.0, 14.0]
azdias['MAINSTREAM_AVANTGARDE'] = np.where(azdias['PRAEGENDE_JUGENDJAHRE'].isin(mainstream), 0,1)
# create a dictionary for decade information from PRAEGENDE_JUGENDJAHRE
decade = {1.0: 1940, 2.0: 1940,
3.0: 1950, 4.0: 1950,
5.0: 1960, 6.0: 1960, 7.0: 1960,
8.0: 1970, 9.0: 1970,
10.0: 1980, 11.0: 1980, 12.0: 1980, 13.0: 1980,
14.0: 1990, 15.0: 1990}
azdias['DECADE'] = azdias['PRAEGENDE_JUGENDJAHRE'].map(decade)
azdias['DECADE'].value_counts()
1990.0 225532 1970.0 175200 1980.0 151770 1960.0 114354 1950.0 74296 1940.0 28157 Name: DECADE, dtype: int64
azdias['MAINSTREAM_AVANTGARDE'].value_counts()
0 594084 1 203983 Name: MAINSTREAM_AVANTGARDE, dtype: int64
azdias['DECADE'].value_counts()
1990.0 225532 1970.0 175200 1980.0 151770 1960.0 114354 1950.0 74296 1940.0 28157 Name: DECADE, dtype: int64
# drop the PRAEGENDE_JUGENDJAHRE column
azdias.drop(['PRAEGENDE_JUGENDJAHRE'], axis=1, inplace=True)
assert('PRAEGENDE_JUGENDJAHRE' not in azdias.columns)
Investigate "CAMEO_INTL_2015" and engineer two new variables.
German CAMEO: Wealth / Life Stage Typology, mapped to international code
"CAMEO_INTL_2015" combines information on two axes: wealth and life stage. Break up the two-digit codes by their 'tens'-place and 'ones'-place digits into two new ordinal variables (which, for the purposes of this project, is equivalent to just treating them as their raw numeric values).
azdias['CAMEO_INTL_2015'].dtypes
dtype('O')
# Change CAMEO_INTL_2015's dtypes to float
azdias['CAMEO_INTL_2015'] = azdias['CAMEO_INTL_2015'].astype(float)
# Create a new variable: WEALTH
azdias.loc[azdias['CAMEO_INTL_2015'].isin([51,52,53,54,55]),'WEALTH']=1
azdias.loc[azdias['CAMEO_INTL_2015'].isin([41,42,43,44,45]),'WEALTH']=2
azdias.loc[azdias['CAMEO_INTL_2015'].isin([31,32,33,34,35]),'WEALTH']=3
azdias.loc[azdias['CAMEO_INTL_2015'].isin([21,22,23,24,25]),'WEALTH']=4
azdias.loc[azdias['CAMEO_INTL_2015'].isin([11,12,13,14,15]),'WEALTH']=5
# Create a new variable: LIFE_STAGE
azdias.loc[azdias['CAMEO_INTL_2015'].isin([11,21,31,41,51]),'LIFE_STAGE']=1
azdias.loc[azdias['CAMEO_INTL_2015'].isin([12,22,32,42,52]),'LIFE_STAGE']=2
azdias.loc[azdias['CAMEO_INTL_2015'].isin([13,23,33,43,53]),'LIFE_STAGE']=3
azdias.loc[azdias['CAMEO_INTL_2015'].isin([14,24,34,44,54]),'LIFE_STAGE']=4
azdias.loc[azdias['CAMEO_INTL_2015'].isin([15,25,35,45,55]),'LIFE_STAGE']=5
# drop CAMEO_INTL_2015 column
azdias.drop(['CAMEO_INTL_2015'], axis=1, inplace=True)
azdias['WEALTH'].value_counts()
1.0 223582 4.0 190689 2.0 189960 5.0 119442 3.0 68193 Name: WEALTH, dtype: int64
azdias['LIFE_STAGE'].value_counts()
1.0 245054 4.0 232777 3.0 119692 5.0 117044 2.0 77299 Name: LIFE_STAGE, dtype: int64
We have 6 mix features (LP_LEBENSPHASE_FEIN, LP_LEBENSPHASE_GROB, PRAEGENDE_JUGENDJAHRE, WOHNLAGE, CAMEO_INTL_2015, PLZ8_BAUMAX).
Given the feature information, I decided to drop LP_LEBENSPHASE_FEIN, because it has similar information with LP_LEBENSPHASE_GROB but it has detailed information.
For WOHNLAGE, it doesn’t have NaN values so I could change dtype as int64. Furthermore, I extracted two new variables from PRAEGENDE_JUGENDJAHRE, MAINSTREAM_AVANTGARDE and DECADE. The former one indicates whether Avantgarde or Mainstream is, and the latter one indicates the year information.
Finally, I created two new variables given CAMEO_INTL_2015 column, WEALTH and LIFE_STAGE. After feature engineering, I dropped two original columns, PRAEGENDE_JUGENDJAHRE and CAMEO_INTL_2015.
In order to finish this step up, you need to make sure that your data frame now only has the columns that you want to keep. To summarize, the dataframe should consist of the following:
Make sure that for any new columns that you have engineered, that you've excluded the original columns from the final dataset. Otherwise, their values will interfere with the analysis later on the project. For example, you should not keep "PRAEGENDE_JUGENDJAHRE", since its values won't be useful for the algorithm: only the values derived from it in the engineered features you created should be retained. As a reminder, your data should only be from the subset with few or no missing values.
We have 77 columns now, but lastly I would like to decide which columns I keep or drop.
len(azdias.columns)
77
We have columns that have similar information each other. For example:
KBA05_GBZ: Number of buildings in the microcell
PLZ8_ANTG1: Number of 1-2 family houses in the PLZ8 region
We would like to drop some columns that have similar information: KBA05_ANTG1, KBA05_ANTG2, KBA05_ANTG3, KBA05_ANTG4, PLZ8_ANTG1, PLZ8_ANTG2, PLZ8_ANTG3, PLZ8_ANTG4.
I will keep columns: KBA05_GBZ, PLZ8_BAUMAX, PLZ8_HHZ, PLZ8_GBZ
drop_cols = ['KBA05_ANTG1', 'KBA05_ANTG2', 'KBA05_ANTG3', 'KBA05_ANTG4',
'PLZ8_ANTG1', 'PLZ8_ANTG2', 'PLZ8_ANTG3', 'PLZ8_ANTG4']
azdias.drop(drop_cols, axis=1, inplace=True)
len(azdias.columns)
69
# check how many missing values columns have
(azdias.isnull().sum()/len(azdias)).sort_values(ascending=False)
REGIOTYP 0.081334 KKK 0.081334 W_KEIT_KIND_HH 0.074311 LP_LEBENSPHASE_GROB 0.059326 KBA05_GBZ 0.050334 MOBI_REGIO 0.050334 SHOPPER_TYP 0.046019 HEALTH_TYP 0.046019 VERS_TYP 0.046019 NATIONALITAET_KZ 0.042506 LP_FAMILIE_GROB 0.039438 DECADE 0.036035 PLZ8_BAUMAX 0.029272 PLZ8_HHZ 0.029272 PLZ8_GBZ 0.029272 KBA13_ANZAHL_PKW 0.015847 ANZ_HAUSHALTE_AKTIV 0.008097 WEALTH 0.007770 CAMEO_DEUG_2015 0.007770 LIFE_STAGE 0.007770 RETOURTYP_BK_S 0.005951 CJT_GESAMTTYP 0.005951 ONLINE_AFFINITAET 0.005951 GFK_URLAUBERTYP 0.005951 LP_STATUS_GROB 0.005951 RELAT_AB 0.005297 ARBEIT 0.005297 ORTSGR_KLS9 0.005170 ANZ_HH_TITEL 0.004835 ALTERSKATEGORIE_GROB 0.003512 INNENSTADT 0.000742 EWDICHTE 0.000742 BALLRAUM 0.000742 KONSUMNAEHE 0.000090 GEBAEUDETYP_RASTER 0.000009 FINANZ_VORSORGER 0.000000 SEMIO_KRIT 0.000000 FINANZTYP 0.000000 SEMIO_RAT 0.000000 FINANZ_HAUSBAUER 0.000000 FINANZ_UNAUFFAELLIGER 0.000000 FINANZ_ANLEGER 0.000000 ANREDE_KZ 0.000000 SEMIO_DOM 0.000000 SEMIO_KULT 0.000000 SEMIO_ERL 0.000000 SEMIO_LUST 0.000000 MAINSTREAM_AVANTGARDE 0.000000 FINANZ_MINIMALIST 0.000000 SEMIO_VERT 0.000000 FINANZ_SPARER 0.000000 SEMIO_KAEM 0.000000 ZABEOTYP 0.000000 SEMIO_FAM 0.000000 ANZ_PERSONEN 0.000000 ANZ_TITEL 0.000000 HH_EINKOMMEN_SCORE 0.000000 SEMIO_SOZ 0.000000 WOHNDAUER_2008 0.000000 SOHO_KZ 0.000000 GEBAEUDETYP 0.000000 SEMIO_PFLICHT 0.000000 SEMIO_MAT 0.000000 MIN_GEBAEUDEJAHR 0.000000 OST_WEST_KZ 0.000000 WOHNLAGE 0.000000 SEMIO_TRADV 0.000000 GREEN_AVANTGARDE 0.000000 SEMIO_REL 0.000000 dtype: float64
Additionally, I decided to drop three columns and the reasons why:
Drop LP_LEBENSPHASE_GROB because it has life stage information in rough scale, and we can get similar information from ALTERSKATEGORIE_GROB (age) and HH_EINKOMMEN_SCORE (income) and LP_FAMILIE_GROB (family type).
Drop GEBAEUDETYP because it has residential or commerical building information which GEBAEUDETYP_RASTER has similar information but with fewer levels of feature.
WOHNLAGE has neighborhood quality information, and I think we can get the similar information from REGIOTYP so, I would like to drop WOHNLAGE
drop_more = ['LP_LEBENSPHASE_GROB', 'GEBAEUDETYP', 'WOHNLAGE']
azdias.drop(drop_more, axis=1, inplace=True)
azdias.head()
| ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | CAMEO_DEUG_2015 | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DECADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1.0 | 2 | 5.0 | 1 | 5 | 2 | 5 | 4 | 5 | 1 | 10.0 | 0 | 3.0 | 3.0 | 1.0 | 1.0 | 1.0 | 5 | 4 | 4 | 3 | 1 | 2 | 2 | 3 | 6 | 4 | 7 | 4 | 7 | 6 | 3.0 | 1.0 | 2.0 | 5 | 2.0 | 0.0 | 6.0 | 3.0 | 9.0 | 11.0 | 0.0 | 1.0 | 1992.0 | 2 | 8 | 1.0 | 6.0 | 3.0 | 8.0 | 3.0 | 2.0 | 1.0 | 3.0 | 3.0 | 963.0 | 1.0 | 5.0 | 4.0 | 3.0 | 5.0 | 4.0 | 0 | 1990.0 | 1.0 | 1.0 |
| 2 | 3.0 | 2 | 3.0 | 1 | 4 | 1 | 2 | 3 | 5 | 1 | 10.0 | 1 | 3.0 | 1.0 | 2.0 | 1.0 | 3.0 | 4 | 1 | 3 | 3 | 4 | 4 | 6 | 3 | 4 | 7 | 7 | 7 | 3 | 3 | 2.0 | 0.0 | 1.0 | 5 | 1.0 | 0.0 | 4.0 | 3.0 | 9.0 | 10.0 | 0.0 | 5.0 | 1992.0 | 2 | 4 | 3.0 | 2.0 | 4.0 | 4.0 | 4.0 | 2.0 | 3.0 | 2.0 | 2.0 | 712.0 | 1.0 | 4.0 | 4.0 | 3.0 | 5.0 | 2.0 | 1 | 1990.0 | 4.0 | 4.0 |
| 3 | 4.0 | 2 | 2.0 | 4 | 2 | 5 | 2 | 1 | 2 | 6 | 1.0 | 0 | 2.0 | NaN | 4.0 | 1.0 | 2.0 | 5 | 1 | 2 | 1 | 4 | 4 | 7 | 4 | 3 | 4 | 4 | 5 | 4 | 4 | 1.0 | 0.0 | 1.0 | 3 | 0.0 | 0.0 | 1.0 | NaN | 9.0 | 1.0 | 0.0 | 4.0 | 1997.0 | 2 | 2 | 4.0 | 4.0 | 2.0 | 6.0 | 4.0 | NaN | 4.0 | 1.0 | NaN | 596.0 | 1.0 | 3.0 | 4.0 | 2.0 | 3.0 | 3.0 | 0 | 1970.0 | 5.0 | 2.0 |
| 4 | 3.0 | 1 | 5.0 | 4 | 3 | 4 | 1 | 3 | 2 | 5 | 5.0 | 0 | 3.0 | 5.0 | 2.0 | 1.0 | 5.0 | 6 | 4 | 4 | 2 | 7 | 4 | 4 | 6 | 2 | 3 | 2 | 2 | 4 | 2 | 2.0 | 0.0 | 2.0 | 4 | 4.0 | 0.0 | 5.0 | 2.0 | 9.0 | 3.0 | 0.0 | 4.0 | 1992.0 | 2 | 6 | 3.0 | 2.0 | 5.0 | 1.0 | 5.0 | 3.0 | 3.0 | 5.0 | 5.0 | 435.0 | 2.0 | 3.0 | 3.0 | 4.0 | 6.0 | 5.0 | 0 | 1970.0 | 2.0 | 3.0 |
| 5 | 1.0 | 2 | 2.0 | 3 | 1 | 5 | 2 | 2 | 5 | 2 | 1.0 | 0 | 3.0 | 1.0 | 2.0 | 1.0 | 3.0 | 2 | 4 | 7 | 4 | 2 | 2 | 2 | 5 | 7 | 4 | 4 | 4 | 7 | 6 | 0.0 | 0.0 | 2.0 | 4 | 1.0 | 0.0 | 5.0 | 6.0 | 9.0 | 5.0 | 0.0 | 5.0 | 1992.0 | 2 | 8 | 4.0 | 6.0 | 2.0 | 7.0 | 4.0 | 4.0 | 4.0 | 1.0 | 5.0 | 1300.0 | 1.0 | 5.0 | 5.0 | 2.0 | 3.0 | 3.0 | 0 | 1950.0 | 1.0 | 4.0 |
azdias.describe()
| ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DECADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 795264.000000 | 798067.000000 | 793318.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 793318.000000 | 798067.000000 | 761341.000000 | 766593.00000 | 793318.000000 | 764144.000000 | 793318.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.00000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 761341.000000 | 798067.000000 | 761341.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 798067.000000 | 738762.000000 | 798067.000000 | 791605.000000 | 794208.000000 | 797995.000000 | 798067.000000 | 798067.000000 | 757897.000000 | 797475.000000 | 797475.000000 | 797475.000000 | 798060.000000 | 733157.000000 | 757897.000000 | 793318.000000 | 733157.000000 | 785420.000000 | 774706.000000 | 774706.000000 | 774706.000000 | 793840.000000 | 793941.000000 | 793840.000000 | 798067.000000 | 769309.000000 | 791866.000000 | 791866.000000 |
| mean | 2.795413 | 1.521486 | 3.502897 | 3.058916 | 2.716050 | 3.432887 | 2.840956 | 2.658361 | 3.114092 | 3.797746 | 7.471247 | 0.219562 | 2.199016 | 2.37719 | 2.460384 | 1.168530 | 3.443105 | 4.139771 | 4.113588 | 3.994586 | 3.887550 | 4.277350 | 4.333779 | 4.622122 | 4.131906 | 3.893826 | 4.54958 | 4.554312 | 4.294274 | 4.184520 | 3.724242 | 1.578632 | 0.008417 | 1.517821 | 3.378584 | 1.728842 | 0.004161 | 4.413465 | 4.161731 | 7.908934 | 8.354955 | 0.040647 | 3.023203 | 1993.276914 | 1.788812 | 3.158580 | 4.153042 | 3.939187 | 4.549482 | 3.738307 | 2.723384 | 2.963540 | 2.732973 | 4.472086 | 619.701328 | 1.943913 | 3.612821 | 3.381087 | 3.166686 | 5.293397 | 3.071032 | 0.255596 | 1973.320083 | 2.737896 | 2.873032 |
| std | 1.018408 | 0.499538 | 1.537613 | 1.377576 | 1.485091 | 1.376869 | 1.472781 | 1.399534 | 1.408110 | 2.084701 | 3.575225 | 0.413950 | 0.755170 | 1.69944 | 1.511672 | 0.474721 | 1.454421 | 1.940928 | 1.913707 | 1.910509 | 1.913197 | 1.945586 | 2.102670 | 1.826790 | 1.957760 | 1.652959 | 1.76037 | 1.826147 | 1.867635 | 1.853878 | 1.765541 | 1.026109 | 0.091355 | 0.499683 | 1.407775 | 1.156529 | 0.068887 | 1.545246 | 1.778827 | 1.923155 | 15.673773 | 0.324029 | 1.550714 | 3.332524 | 0.408152 | 1.329537 | 2.183712 | 1.718989 | 2.028918 | 0.923188 | 0.979867 | 1.428882 | 1.555709 | 1.836357 | 340.034520 | 1.459654 | 0.973967 | 1.111598 | 0.999069 | 2.303376 | 1.360533 | 0.436196 | 14.574120 | 1.464493 | 1.484771 |
| min | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1.000000 | 1.00000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.00000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 0.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1.000000 | 1985.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1.000000 | 0.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 1.000000 | 0.000000 | 1940.000000 | 1.000000 | 1.000000 |
| 25% | 2.000000 | 1.000000 | 2.000000 | 2.000000 | 1.000000 | 2.000000 | 1.000000 | 1.000000 | 2.000000 | 2.000000 | 4.000000 | 0.000000 | 2.000000 | 1.00000 | 1.000000 | 1.000000 | 2.000000 | 2.000000 | 2.000000 | 3.000000 | 2.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 3.000000 | 3.00000 | 3.000000 | 3.000000 | 3.000000 | 2.000000 | 1.000000 | 0.000000 | 1.000000 | 3.000000 | 1.000000 | 0.000000 | 3.000000 | 3.000000 | 8.000000 | 2.000000 | 0.000000 | 2.000000 | 1992.000000 | 2.000000 | 2.000000 | 2.000000 | 2.000000 | 3.000000 | 3.000000 | 2.000000 | 2.000000 | 1.000000 | 3.000000 | 384.000000 | 1.000000 | 3.000000 | 3.000000 | 3.000000 | 4.000000 | 2.000000 | 0.000000 | 1960.000000 | 1.000000 | 1.000000 |
| 50% | 3.000000 | 2.000000 | 4.000000 | 3.000000 | 3.000000 | 4.000000 | 3.000000 | 2.000000 | 3.000000 | 4.000000 | 8.000000 | 0.000000 | 2.000000 | 1.00000 | 2.000000 | 1.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 4.000000 | 5.000000 | 5.000000 | 4.000000 | 4.000000 | 4.000000 | 5.00000 | 5.000000 | 4.000000 | 4.000000 | 4.000000 | 2.000000 | 0.000000 | 2.000000 | 3.000000 | 1.000000 | 0.000000 | 5.000000 | 4.000000 | 9.000000 | 4.000000 | 0.000000 | 3.000000 | 1992.000000 | 2.000000 | 3.000000 | 5.000000 | 4.000000 | 5.000000 | 4.000000 | 3.000000 | 3.000000 | 3.000000 | 5.000000 | 549.000000 | 1.000000 | 4.000000 | 3.000000 | 3.000000 | 5.000000 | 3.000000 | 0.000000 | 1970.000000 | 2.000000 | 3.000000 |
| 75% | 4.000000 | 2.000000 | 5.000000 | 4.000000 | 4.000000 | 5.000000 | 4.000000 | 4.000000 | 4.000000 | 6.000000 | 11.000000 | 0.000000 | 3.000000 | 4.00000 | 4.000000 | 1.000000 | 5.000000 | 6.000000 | 6.000000 | 5.000000 | 5.000000 | 6.000000 | 6.000000 | 6.000000 | 6.000000 | 5.000000 | 6.00000 | 6.000000 | 6.000000 | 6.000000 | 5.000000 | 2.000000 | 0.000000 | 2.000000 | 4.000000 | 2.000000 | 0.000000 | 6.000000 | 6.000000 | 9.000000 | 10.000000 | 0.000000 | 4.000000 | 1993.000000 | 2.000000 | 4.000000 | 6.000000 | 6.000000 | 6.000000 | 4.000000 | 3.000000 | 4.000000 | 4.000000 | 6.000000 | 778.000000 | 3.000000 | 4.000000 | 4.000000 | 4.000000 | 7.000000 | 4.000000 | 1.000000 | 1990.000000 | 4.000000 | 4.000000 |
| max | 4.000000 | 2.000000 | 6.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 6.000000 | 12.000000 | 1.000000 | 3.000000 | 5.00000 | 5.000000 | 3.000000 | 5.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 7.00000 | 7.000000 | 7.000000 | 7.000000 | 7.000000 | 3.000000 | 1.000000 | 2.000000 | 6.000000 | 45.000000 | 6.000000 | 6.000000 | 6.000000 | 9.000000 | 595.000000 | 23.000000 | 7.000000 | 2016.000000 | 2.000000 | 5.000000 | 7.000000 | 6.000000 | 8.000000 | 5.000000 | 4.000000 | 6.000000 | 5.000000 | 7.000000 | 2300.000000 | 5.000000 | 5.000000 | 5.000000 | 5.000000 | 9.000000 | 5.000000 | 1.000000 | 1990.000000 | 5.000000 | 5.000000 |
Finally, I will use 66 columns for further analysis.
len(azdias.columns)
66
Even though you've finished cleaning up the general population demographics data, it's important to look ahead to the future and realize that you'll need to perform the same cleaning steps on the customer demographics data. In this substep, complete the function below to execute the main feature selection, encoding, and re-engineering steps you performed above. Then, when it comes to looking at the customer data in Step 3, you can just run this function on that DataFrame to get the trimmed dataset in a single step.
def clean_data(df_path):
"""
Perform feature trimming, re-encoding, and engineering for demographics
data
INPUT: Demographics DataFrame
OUTPUT: Trimmed and cleaned demographics DataFrame
"""
# load data
df = pd.read_csv(df_path/'Udacity_AZDIAS_Subset.csv', delimiter=';')
feat_info = pd.read_csv(df_path/'AZDIAS_Feature_Summary.csv', delimiter=';')
print("Original dataset shape: {}".format(df.shape))
## create lists for missing value types
for i in range(df.shape[1]):
col_name = df.columns[i]
missing_list = feat_info.iloc[i, 3]
missing_list = missing_list.strip('[]').split(',')
if missing_list == ['']: continue
else:
for mc in missing_list:
if df[col_name].dtype=='object':
df.loc[df[col_name]==mc, col_name] = np.nan
else:
mc = int(mc)
df.loc[df[col_name]==mc, col_name] = np.nan
## remove the columns which have more than 30% of missing values
# create a dataframe for missing value percent
missing_cols_df = pd.DataFrame((df.isnull().sum()/len(df)*100), columns=['percent'])
missing_threshold = 30 # set up the threshold for dropping columns
drop_missing_cols = missing_cols_df[missing_cols_df['percent']>30].index
print("\nI will drop columns because they have more than 30% of missing values in columns:\n", drop_missing_cols.tolist())
df = df.drop(drop_missing_cols, axis=1)
print("\nDataset after dropped columns which have more than 30% of missing values: ", df.shape)
## remove the rows which have more than 30% of missing values
missing_rows = df[df.isnull().sum(axis=1)>30]
df = df.drop(missing_rows.index, axis=0)
print("\nDataset after dropped rows which have more than 30% of missing values: ", df.shape)
## re-encode "OST_WEST_KZ" value (W: west, O: east) as 1, 2
df['OST_WEST_KZ'] = df['OST_WEST_KZ'].map({'O':1, 'W':2})
## feature engineering for PRAEGENDE_JUGENDJAHRE
# create a column for mainstream with value 0, 1
mainstream = [1.0, 3.0, 5.0, 8.0, 10., 12.0, 14.0]
df['MAINSTREAM_AVANTGARDE'] = np.where(df['PRAEGENDE_JUGENDJAHRE'].isin(mainstream), 0, 1)
# create a dictionary for decade information from PRAEGENDE_JUGENDJAHRE
decade = {1.0: 1940, 2.0: 1940,
3.0: 1950, 4.0: 1950,
5.0: 1960, 6.0: 1960, 7.0: 1960,
8.0: 1970, 9.0: 1970,
10.0: 1980, 11.0: 1980, 12.0: 1980, 13.0: 1980,
14.0: 1990, 15.0: 1990}
df['DACADE'] = df['PRAEGENDE_JUGENDJAHRE'].map(decade)
## feature engineering for CAMEO_INTL_2015
# change CAMEO_INTL_2015's dtypes to float
df['CAMEO_INTL_2015'] = df['CAMEO_INTL_2015'].astype(float)
# Create a new variable: WEALTH
df.loc[df['CAMEO_INTL_2015'].isin([51,52,53,54,55]),'WEALTH']=1
df.loc[df['CAMEO_INTL_2015'].isin([41,42,43,44,45]),'WEALTH']=2
df.loc[df['CAMEO_INTL_2015'].isin([31,32,33,34,35]),'WEALTH']=3
df.loc[df['CAMEO_INTL_2015'].isin([21,22,23,24,25]),'WEALTH']=4
df.loc[df['CAMEO_INTL_2015'].isin([11,12,13,14,15]),'WEALTH']=5
# Create a new variable: LIFE_STAGE
df.loc[df['CAMEO_INTL_2015'].isin([11,21,31,41,51]),'LIFE_STAGE']=1
df.loc[df['CAMEO_INTL_2015'].isin([12,22,32,42,52]),'LIFE_STAGE']=2
df.loc[df['CAMEO_INTL_2015'].isin([13,23,33,43,53]),'LIFE_STAGE']=3
df.loc[df['CAMEO_INTL_2015'].isin([14,24,34,44,54]),'LIFE_STAGE']=4
df.loc[df['CAMEO_INTL_2015'].isin([15,25,35,45,55]),'LIFE_STAGE']=5
## Drop reduntant columns
drop_cols = ['LP_FAMILIE_FEIN', 'LP_STATUS_FEIN', 'CAMEO_DEU_2015',
'LP_LEBENSPHASE_FEIN', 'PRAEGENDE_JUGENDJAHRE', 'CAMEO_INTL_2015',
'KBA05_ANTG1', 'KBA05_ANTG2', 'KBA05_ANTG3', 'KBA05_ANTG4',
'PLZ8_ANTG1', 'PLZ8_ANTG2', 'PLZ8_ANTG3', 'PLZ8_ANTG4',
'LP_LEBENSPHASE_GROB', 'GEBAEUDETYP', 'WOHNLAGE']
df = df.drop(drop_cols, axis=1)
print("\nDropped {} redundant columns".format(len(drop_cols)))
print("\nFinal dataset's shape: ", df.shape)
## Return the cleaned dataframe.
return df, feat_info
df, feat_info = clean_data(path)
Original dataset shape: (891221, 85) I will drop columns because they have more than 30% of missing values in columns: ['AGER_TYP', 'GEBURTSJAHR', 'TITEL_KZ', 'ALTER_HH', 'KK_KUNDENTYP', 'KBA05_BAUMAX'] Dataset after dropped columns which have more than 30% of missing values: (891221, 79) Dataset after dropped rows which have more than 30% of missing values: (798067, 79) Dropped 17 redundant columns Final dataset's shape: (798067, 66)
Before we apply dimensionality reduction techniques to the data, we need to perform feature scaling so that the principal component vectors are not influenced by the natural differences in scale for features. Starting from this part of the project, you'll want to keep an eye on the API reference page for sklearn to help you navigate to all of the classes and functions that you'll need. In this substep, you'll need to check the following:
.fit_transform() method to both fit a procedure to the data as well as apply the transformation to the data at the same time. Don't forget to keep the fit sklearn objects handy, since you'll be applying them to the customer demographics data towards the end of the project.# Figure how many missing values left?
(df.isnull().sum()).sort_values(ascending=False)
REGIOTYP 64910 KKK 64910 W_KEIT_KIND_HH 59305 KBA05_GBZ 40170 MOBI_REGIO 40170 SHOPPER_TYP 36726 HEALTH_TYP 36726 VERS_TYP 36726 NATIONALITAET_KZ 33923 LP_FAMILIE_GROB 31474 DACADE 28758 PLZ8_HHZ 23361 PLZ8_BAUMAX 23361 PLZ8_GBZ 23361 KBA13_ANZAHL_PKW 12647 ANZ_HAUSHALTE_AKTIV 6462 WEALTH 6201 CAMEO_DEUG_2015 6201 LIFE_STAGE 6201 RETOURTYP_BK_S 4749 CJT_GESAMTTYP 4749 ONLINE_AFFINITAET 4749 GFK_URLAUBERTYP 4749 LP_STATUS_GROB 4749 RELAT_AB 4227 ARBEIT 4227 ORTSGR_KLS9 4126 ANZ_HH_TITEL 3859 ALTERSKATEGORIE_GROB 2803 INNENSTADT 592 EWDICHTE 592 BALLRAUM 592 KONSUMNAEHE 72 GEBAEUDETYP_RASTER 7 ANREDE_KZ 0 SEMIO_VERT 0 FINANZ_MINIMALIST 0 MAINSTREAM_AVANTGARDE 0 SEMIO_LUST 0 SEMIO_ERL 0 SEMIO_KULT 0 FINANZ_SPARER 0 FINANZ_VORSORGER 0 FINANZ_ANLEGER 0 FINANZ_UNAUFFAELLIGER 0 FINANZ_HAUSBAUER 0 SEMIO_RAT 0 FINANZTYP 0 SEMIO_KRIT 0 SEMIO_DOM 0 ZABEOTYP 0 SEMIO_KAEM 0 SEMIO_PFLICHT 0 GREEN_AVANTGARDE 0 SEMIO_TRADV 0 OST_WEST_KZ 0 MIN_GEBAEUDEJAHR 0 SEMIO_MAT 0 SEMIO_FAM 0 SOHO_KZ 0 WOHNDAUER_2008 0 SEMIO_SOZ 0 HH_EINKOMMEN_SCORE 0 ANZ_TITEL 0 ANZ_PERSONEN 0 SEMIO_REL 0 dtype: int64
# create lists of feature variables depending on dtypes
num_feats = []
cat_feats = []
mix_feats = []
for i in range(feat_info.shape[0]):
if feat_info['type'][i] == 'ordinal':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'numeric':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'interval':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'categorical':
cat_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'mixed':
mix_feats.append(feat_info['attribute'][i])
len(num_feats), len(cat_feats), len(mix_feats)
(57, 21, 7)
# create column lists that we need to deal with
copy = df.copy()
copy.drop(copy.columns[copy.apply(lambda col: col.isnull().sum() == 0)], axis=1, inplace=True)
nan_lists = list(copy.columns)
# Create column lists that are numerical variables and have NaN values
nan_num_list = list(set(num_feats).intersection(set(nan_lists)))
# Create column lists that are categorical and mixed variables and have NaN values
nan_cat_list = list(set(cat_feats).intersection(set(nan_lists)))
nan_mix_list = list(set(mix_feats).intersection(set(nan_lists)))
nan_num_list
['KKK', 'RELAT_AB', 'HEALTH_TYP', 'INNENSTADT', 'GEBAEUDETYP_RASTER', 'PLZ8_GBZ', 'ANZ_HAUSHALTE_AKTIV', 'MOBI_REGIO', 'KBA05_GBZ', 'REGIOTYP', 'ARBEIT', 'W_KEIT_KIND_HH', 'RETOURTYP_BK_S', 'ALTERSKATEGORIE_GROB', 'ANZ_HH_TITEL', 'ORTSGR_KLS9', 'EWDICHTE', 'ONLINE_AFFINITAET', 'PLZ8_HHZ', 'KBA13_ANZAHL_PKW', 'BALLRAUM', 'KONSUMNAEHE']
nan_cat_list
['SHOPPER_TYP', 'VERS_TYP', 'CAMEO_DEUG_2015', 'NATIONALITAET_KZ', 'LP_STATUS_GROB', 'GFK_URLAUBERTYP', 'LP_FAMILIE_GROB', 'CJT_GESAMTTYP']
nan_mix_list
['PLZ8_BAUMAX']
# 2) Impute missing values by using mode for categorical variables and median for numerical variables (nan_num_list)
# create df_impute dataframe and keep df as original dataframe
df_impute = df.copy()
# Impute NaNs in numerical variables by using median
imp_median = SimpleImputer(missing_values=np.nan, strategy='median')
df_impute[['ORTSGR_KLS9','INNENSTADT', 'ARBEIT', 'RELAT_AB', 'RETOURTYP_BK_S',
'GEBAEUDETYP_RASTER', 'ONLINE_AFFINITAET', 'REGIOTYP', 'KONSUMNAEHE', 'W_KEIT_KIND_HH',
'KBA13_ANZAHL_PKW', 'ANZ_HH_TITEL', 'KKK', 'ANZ_HAUSHALTE_AKTIV', 'MOBI_REGIO',
'HEALTH_TYP', 'ALTERSKATEGORIE_GROB', 'KBA05_GBZ', 'EWDICHTE', 'BALLRAUM',
'PLZ8_GBZ', 'PLZ8_HHZ']] = imp_median.fit_transform(df_impute[['ORTSGR_KLS9','INNENSTADT', 'ARBEIT', 'RELAT_AB',
'RETOURTYP_BK_S', 'GEBAEUDETYP_RASTER', 'ONLINE_AFFINITAET',
'REGIOTYP', 'KONSUMNAEHE', 'W_KEIT_KIND_HH', 'KBA13_ANZAHL_PKW',
'ANZ_HH_TITEL', 'KKK', 'ANZ_HAUSHALTE_AKTIV', 'MOBI_REGIO',
'HEALTH_TYP', 'ALTERSKATEGORIE_GROB', 'KBA05_GBZ',
'EWDICHTE', 'BALLRAUM', 'PLZ8_GBZ', 'PLZ8_HHZ']])
# Impute NaNs in categorical and mixed variables by using mode
imp_mode = SimpleImputer(missing_values=np.nan, strategy='most_frequent')
df_impute[['CJT_GESAMTTYP', 'VERS_TYP', 'LP_STATUS_GROB', 'NATIONALITAET_KZ',
'GFK_URLAUBERTYP', 'LP_FAMILIE_GROB', 'SHOPPER_TYP', 'CAMEO_DEUG_2015', 'PLZ8_BAUMAX',
'DACADE', 'WEALTH', 'LIFE_STAGE']] = imp_mode.fit_transform(df_impute[['CJT_GESAMTTYP', 'VERS_TYP', 'LP_STATUS_GROB', 'NATIONALITAET_KZ',
'GFK_URLAUBERTYP', 'LP_FAMILIE_GROB', 'SHOPPER_TYP', 'CAMEO_DEUG_2015', 'PLZ8_BAUMAX',
'DACADE', 'WEALTH', 'LIFE_STAGE']])
# save columns' name for later scaling processing
df_cols = df_impute.columns
# Apply feature scaling to the general population demographics data.
scaler = StandardScaler()
df_impute = scaler.fit_transform(df_impute)
df_impute = pd.DataFrame(df_impute, columns=df_cols)
df_impute.head()
| ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | CAMEO_DEUG_2015 | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DACADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | -1.766647 | 0.957912 | 0.974332 | -1.494594 | 1.537920 | -1.040686 | 1.465965 | 0.958633 | 1.339319 | -1.342038 | 0.698526 | -0.530407 | 1.096615 | 0.401372 | -0.960530 | -0.346454 | -1.686349 | 0.443205 | -0.059355 | 0.002834 | -0.463909 | -1.684507 | -1.109913 | -1.435372 | -0.578164 | 1.274185 | -0.312196 | 1.339262 | -0.157565 | 1.518699 | 1.288987 | 1.434333 | 10.85417 | 0.922940 | 1.151759 | 0.234458 | -0.060408 | 1.026720 | -0.671568 | 0.567332 | 0.171649 | -0.125133 | -1.304750 | -0.383167 | 0.517425 | 0.981383 | -1.659274 | 0.845768 | -0.546589 | 1.701105 | -0.799742 | -0.791629 | -1.411422 | 0.171117 | -0.857885 | 1.020668 | -0.63327 | 1.430458 | 0.574309 | -0.166387 | -0.127042 | 0.684885 | -0.585967 | 1.098064 | -1.175655 | -1.248888 |
| 1 | 0.200522 | 0.957912 | -0.329868 | -1.494594 | 0.864560 | -1.766972 | -0.570999 | 0.244109 | 1.339319 | -1.342038 | 0.698526 | 1.885345 | 1.096615 | -0.784149 | -0.298869 | -0.346454 | -0.307722 | -0.072013 | -1.626994 | -0.520587 | -0.463909 | -0.142554 | -0.158741 | 0.754262 | -0.578164 | 0.064233 | 1.391992 | 1.339262 | 1.448745 | -0.638942 | -0.410210 | 0.443769 | -0.09213 | -1.083494 | 1.151759 | -0.630198 | -0.060408 | -0.267573 | -0.671568 | 0.567332 | 0.107608 | -0.125133 | 1.274826 | -0.383167 | 0.517425 | -0.625339 | -0.116192 | -0.986554 | 0.035364 | -0.271086 | 0.283466 | -0.791629 | 0.024866 | -0.473542 | -1.424136 | 0.276843 | -0.63327 | 0.390764 | 0.574309 | -0.166387 | -0.127042 | -0.789025 | 1.706581 | 1.098064 | 0.869682 | 0.767097 |
| 2 | 1.184107 | 0.957912 | -0.981968 | 0.683145 | -0.482159 | 1.138172 | -0.570999 | -1.184938 | -0.791197 | 1.056389 | -1.814355 | -0.530407 | -0.256992 | -0.784149 | 1.024455 | -0.346454 | -0.997036 | 0.443205 | -1.626994 | -1.044008 | -1.509281 | -0.142554 | -0.158741 | 1.301671 | -0.067376 | -0.540743 | -0.312196 | -0.303542 | 0.377872 | -0.099532 | 0.156189 | -0.546795 | -0.09213 | -1.083494 | -0.268923 | -1.494855 | -0.060408 | -2.209012 | -0.087450 | 0.567332 | -0.468759 | -0.125133 | 0.629932 | 1.117198 | 0.517425 | -1.428699 | 0.655349 | -0.070393 | -1.128543 | 0.715010 | 0.283466 | 0.269703 | 0.743009 | -1.118201 | 0.274619 | -0.066917 | -0.63327 | -0.648929 | 0.574309 | -1.169906 | -0.997550 | -0.052070 | -0.585967 | -0.267784 | 1.551461 | -0.576893 |
| 3 | 0.200522 | -1.043937 | 0.974332 | 0.683145 | 0.191200 | 0.411886 | -1.249987 | 0.244109 | -0.791197 | 0.576704 | -0.697519 | -0.530407 | 1.096615 | 1.586893 | -0.298869 | -0.346454 | 1.070905 | 0.958423 | -0.059355 | 0.002834 | -0.986595 | 1.399399 | -0.158741 | -0.340555 | 0.954200 | -1.145720 | -0.880259 | -1.398745 | -1.228438 | -0.099532 | -0.976609 | 0.443769 | -0.09213 | 0.922940 | 0.441418 | 1.963772 | -0.060408 | 0.379574 | -1.255686 | 0.567332 | -0.340677 | -0.125133 | 0.629932 | -0.383167 | 0.517425 | 0.178022 | -0.116192 | -0.986554 | 0.617318 | -1.750229 | 1.366673 | 0.269703 | 0.024866 | 1.460434 | 0.274619 | -0.544032 | 0.05786 | -0.648929 | -0.337194 | 0.837133 | 0.308212 | 1.421840 | -0.585967 | -0.267784 | -0.493876 | 0.095102 |
| 4 | -1.766647 | 0.957912 | -0.981968 | -0.042768 | -1.155519 | 1.138172 | -0.570999 | -0.470414 | 1.339319 | -0.862353 | -1.814355 | -0.530407 | 1.096615 | -0.784149 | -0.298869 | -0.346454 | -0.307722 | -1.102449 | -0.059355 | 1.573097 | 0.058776 | -1.170522 | -1.109913 | -1.435372 | 0.443412 | 1.879161 | -0.312196 | -0.303542 | -0.157565 | 1.518699 | 1.288987 | -1.537359 | -0.09213 | 0.922940 | 0.441418 | -0.630198 | -0.060408 | 0.379574 | 1.080786 | 0.567332 | -0.212596 | -0.125133 | 1.274826 | -0.383167 | 0.517425 | 0.981383 | 0.655349 | 0.845768 | -1.128543 | 1.208058 | 0.283466 | 1.331035 | 0.743009 | -1.118201 | 0.274619 | 2.019350 | -0.63327 | 1.430458 | 1.485812 | -1.169906 | -0.997550 | -0.052070 | -0.585967 | -1.633632 | -1.175655 | 0.767097 |
df_impute.shape
(798067, 66)
I created two dataframes. df_remove doesn't have any NaN values by dropping all NaN values. In the other hand, df_impute doesn't have any NaN values but by filling NaN with median for numerical variables and with mode for categorical variables. After I created two dataframes, I created dummy columns for categorical variables on each dataframe. After that, I performed feature scaling.
On your scaled data, you are now ready to apply dimensionality reduction techniques.
plot() function. Based on what you find, select a value for the number of transformed features you'll retain for the clustering part of the project.# Apply PCA to the data.
from sklearn.decomposition import PCA
pca = PCA()
df_impute_pca = pca.fit_transform(df_impute)
#df_remove_pca = pca.fit_transform(df_remove)
# Investigate the variance accounted for by each principal component.
def scree_plot(pca):
"""
Create a scree plot associated with the principal components
INPUTS
pca - the result of instantian of PCA in scikit learn
"""
num_components = len(pca.explained_variance_ratio_)
idx = np.arange(num_components)
vals = pca.explained_variance_ratio_
plt.figure(figsize=(10,6))
ax = plt.subplot(111)
cumvals = np.cumsum(vals)
ax.bar(idx, vals)
ax.plot(idx, cumvals)
for i in range(num_components):
ax.annotate(r"%s%%" % ((str(vals[i]*100)[:4])), (idx[i]+0.2, vals[i]), va='bottom', ha='center', fontsize=12)
ax.xaxis.set_tick_params(width=0)
ax.yaxis.set_tick_params(width=2, length=12)
ax.set_xlabel("Principal Component")
ax.set_ylabel("Variance Explained (%)")
plt.title("Explained Variance Per Principal Component")
scree_plot(pca)
When we have 63 components, pca's result shows 91%
explained_var = pca.explained_variance_ratio_
explained_var2 = sum([explained_var[i] for i in range(2)])
explained_var4 = sum([explained_var[i] for i in range(4)])
explained_var10 = sum([explained_var[i] for i in range(10)])
explained_var20 = sum([explained_var[i] for i in range(20)])
explained_var40 = sum([explained_var[i] for i in range(40)])
print("Total Variance from first 2 components:", explained_var2)
print("Total Variance from first 4 components:", explained_var4)
print("Total Variance from first 10 components:", explained_var10)
print("Total Variance from first 20 components:", explained_var20)
print("Total Variance from first 40 components:", explained_var40)
Total Variance from first 2 components: 0.2849537113812102 Total Variance from first 4 components: 0.43058316677760144 Total Variance from first 10 components: 0.5949221082128853 Total Variance from first 20 components: 0.7589802830066357 Total Variance from first 40 components: 0.9297079956683358
# Re-apply PCA to the data while selecting for number of components to retain.
def do_pca(n_components, data):
"""
Transforms data using PCA to create n_components, and provides back the results of the transformation.
INPUT
n_components (int): the number of principal components to create
data: the data you would like to transform
OUTPUT
pca: the pca object created after fitting the data
X_pca: the transformed X matrix with new number of components
"""
X = data
pca = PCA(n_components)
X_pca = pca.fit_transform(X)
return pca, X_pca
# PCA with n_components=40
pca_40, X_pca_40 = do_pca(40, df_impute)
X_pca_40.shape
(798067, 40)
Given the scree graph above, I chose 40 components which explains more than 90% of the variance.
Now that we have our transformed principal components, it's a nice idea to check out the weight of each variable on the first few components to see if they can be interpreted in some fashion.
As a reminder, each principal component is a unit vector that points in the direction of highest variance (after accounting for the variance captured by earlier principal components). The further a weight is from zero, the more the principal component is in the direction of the corresponding feature. If two features have large weights of the same sign (both positive or both negative), then increases in one tend expect to be associated with increases in the other. To contrast, features with different signs can be expected to show a negative correlation: increases in one variable should result in a decrease in the other.
# Map weights for the first principal component to corresponding feature names
# and then print the linked values, sorted by weight.
# HINT: Try defining a function here or in a new cell that you can reuse in the
# other cells.
def pca_results(full_dataset, pca):
""" Create a DataFrame of the PCA results,
including dimension feature weights and explained variance.
INPUT:
full_dataset (dataframe): dataframe that you want to perform PCA
pca: the pca object created after fitting the data
"""
# Dimension indexing
dimensions = ['D{}'.format(i) for i in range(1, len(pca.components_)+1)]
# PCA Components
components = pd.DataFrame(np.round(pca.components_, 4), columns=full_dataset.keys())
components.index = dimensions
# PCA explained variance
ratios = pca.explained_variance_ratio_.reshape(len(pca.components_), 1)
variance_ratios = pd.DataFrame(np.round(ratios, 4), columns=['Explained Variance'])
variance_ratios.index = dimensions
# return a concatenated dataframe
return pd.concat([variance_ratios, components], axis=1)
pca_results(df_impute, pca_40)
| Explained Variance | ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | CAMEO_DEUG_2015 | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DACADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| D1 | 0.1566 | -0.2066 | -0.0024 | 0.0923 | -0.2446 | 0.2280 | -0.1929 | 0.1523 | 0.1554 | 0.1205 | -0.1081 | 0.0784 | -0.1120 | 0.0495 | -0.0557 | -0.2118 | 0.0831 | -0.0816 | 0.0585 | 0.1220 | 0.1918 | 0.1237 | -0.0362 | -0.1341 | -0.1400 | 0.1310 | 0.1595 | -0.0181 | 0.0131 | 0.0157 | 0.1933 | 0.1667 | -0.0468 | -0.0016 | 0.0221 | 0.1474 | -0.0609 | -0.0084 | 0.1834 | -0.0063 | -0.0803 | 0.1066 | 0.0202 | -0.1242 | -0.0342 | -0.0378 | 0.1778 | -0.1641 | -0.0904 | 0.1395 | -0.1196 | -0.0913 | 0.0468 | -0.1886 | 0.0125 | 0.0647 | -0.0638 | 0.1583 | 0.0250 | -0.1252 | 0.1067 | 0.1429 | 0.0995 | -0.0962 | 0.1893 | -0.1719 | -0.1226 |
| D2 | 0.1283 | 0.1835 | 0.1081 | -0.0939 | -0.0461 | -0.1483 | 0.1592 | -0.1442 | -0.1771 | 0.1854 | 0.0662 | 0.0009 | -0.0788 | -0.0364 | -0.1119 | -0.1337 | -0.0337 | 0.1365 | -0.0921 | -0.1516 | -0.1912 | -0.1212 | -0.1037 | 0.1332 | 0.1916 | -0.1834 | -0.1041 | 0.1270 | 0.0930 | 0.1392 | -0.1552 | -0.1703 | 0.0998 | -0.0031 | 0.0415 | 0.0623 | -0.1063 | 0.0021 | 0.1543 | 0.1322 | 0.0251 | 0.1183 | 0.0430 | -0.1279 | -0.0725 | -0.0504 | 0.1631 | -0.1636 | -0.1027 | 0.1568 | -0.1317 | -0.0887 | 0.0278 | -0.1781 | -0.1818 | 0.0536 | -0.0742 | 0.1589 | 0.0152 | -0.1337 | 0.1241 | 0.1582 | 0.1147 | -0.0639 | -0.1735 | -0.1648 | -0.0582 |
| D3 | 0.0940 | 0.0691 | -0.3572 | -0.0413 | 0.1261 | -0.0942 | 0.0921 | -0.1800 | -0.1049 | -0.0127 | 0.1170 | -0.0135 | 0.0178 | -0.0160 | -0.0441 | 0.0007 | -0.0177 | 0.1112 | 0.2571 | 0.2496 | 0.0769 | 0.0593 | 0.3269 | 0.0573 | -0.1758 | 0.2350 | -0.2052 | -0.2641 | -0.3036 | -0.3220 | -0.0675 | -0.0736 | -0.1201 | -0.0003 | 0.0116 | -0.0392 | -0.0314 | 0.0075 | 0.0211 | 0.1058 | 0.0256 | 0.0477 | 0.0187 | -0.0582 | -0.0316 | -0.0313 | 0.0667 | -0.0540 | -0.0497 | 0.0691 | -0.0643 | -0.0473 | -0.0005 | -0.0627 | -0.0752 | 0.0116 | -0.0439 | 0.0766 | -0.0011 | -0.0659 | 0.0609 | 0.0719 | 0.0520 | 0.0088 | -0.1049 | -0.0660 | -0.0313 |
| D4 | 0.0516 | -0.0347 | 0.0271 | 0.0792 | 0.0415 | 0.0045 | -0.0185 | -0.1231 | 0.0730 | -0.0722 | -0.0162 | -0.0343 | 0.3676 | -0.0012 | 0.1223 | 0.1240 | 0.0026 | 0.0217 | 0.0172 | -0.0092 | 0.0046 | 0.0161 | -0.0103 | 0.0150 | -0.0222 | -0.0268 | 0.0418 | 0.0008 | 0.0997 | 0.0786 | 0.0192 | 0.0438 | 0.0494 | 0.0028 | 0.0278 | -0.1140 | 0.1230 | 0.0508 | -0.2144 | -0.0937 | 0.0201 | 0.0166 | 0.0553 | -0.1708 | -0.0291 | 0.0788 | -0.0954 | -0.0021 | -0.2727 | 0.3012 | -0.2649 | -0.1154 | -0.2488 | 0.0077 | 0.1323 | -0.1829 | -0.0068 | 0.1125 | 0.1023 | -0.0270 | 0.0931 | 0.2942 | 0.1255 | 0.3561 | 0.0377 | 0.0978 | 0.0481 |
| D5 | 0.0383 | 0.0144 | 0.0056 | 0.0697 | 0.0878 | -0.0080 | -0.0511 | 0.0653 | -0.0777 | -0.0970 | 0.1389 | -0.0269 | -0.0198 | 0.0215 | 0.2713 | 0.0764 | -0.0037 | -0.0414 | -0.0020 | -0.0414 | -0.0308 | -0.0536 | 0.0081 | -0.0294 | 0.0388 | 0.0149 | -0.0147 | -0.0312 | 0.0085 | 0.0330 | -0.0107 | -0.0357 | 0.0374 | 0.0053 | -0.0171 | -0.0421 | 0.2602 | -0.0121 | -0.0152 | -0.2222 | 0.0747 | -0.0474 | -0.0501 | 0.1179 | 0.0600 | -0.2112 | 0.0485 | 0.0577 | 0.0081 | 0.0010 | -0.0319 | 0.0737 | 0.2023 | 0.0637 | 0.1651 | 0.1500 | -0.4307 | 0.0876 | -0.4153 | -0.3528 | 0.1936 | 0.0456 | 0.1249 | -0.0442 | 0.0218 | -0.0484 | -0.0206 |
| D6 | 0.0307 | 0.0697 | -0.0380 | 0.0974 | -0.0217 | 0.0229 | 0.0478 | 0.0357 | 0.0013 | -0.0248 | -0.0196 | -0.0073 | -0.0792 | 0.0273 | 0.3850 | -0.0564 | 0.0102 | 0.0019 | 0.0268 | -0.0179 | -0.0533 | -0.1176 | 0.0355 | 0.0404 | 0.0556 | 0.0066 | -0.1031 | -0.0688 | -0.0358 | 0.0030 | -0.0464 | -0.1261 | 0.0229 | 0.0081 | 0.0760 | -0.0304 | 0.3774 | -0.0147 | 0.0678 | -0.2804 | 0.1161 | 0.0487 | -0.0176 | -0.0593 | -0.0311 | 0.1352 | 0.1260 | -0.1071 | -0.0234 | 0.0434 | -0.0130 | 0.0181 | 0.2307 | -0.0835 | 0.1648 | 0.2315 | 0.3326 | -0.0170 | 0.3431 | 0.2259 | -0.0385 | 0.0328 | -0.0032 | -0.0766 | 0.0290 | -0.1204 | -0.1216 |
| D7 | 0.0266 | 0.0541 | 0.0274 | -0.0116 | -0.1172 | 0.0152 | -0.0288 | 0.0348 | -0.0407 | 0.1893 | 0.0006 | 0.0136 | -0.0362 | -0.1994 | 0.2133 | -0.1127 | -0.0081 | -0.0737 | 0.0101 | 0.0067 | -0.0405 | 0.1081 | 0.0260 | 0.0957 | 0.0164 | -0.0812 | -0.0037 | -0.1105 | -0.0451 | -0.0674 | -0.0868 | 0.0236 | 0.0698 | 0.0051 | -0.1695 | -0.0534 | 0.2084 | 0.1048 | 0.0363 | -0.1477 | 0.0532 | 0.2292 | 0.2408 | -0.0676 | -0.0412 | -0.1768 | 0.0266 | -0.1241 | 0.1198 | -0.1602 | 0.1270 | -0.2000 | -0.3469 | -0.1265 | 0.0750 | -0.3720 | -0.0297 | 0.1040 | -0.0656 | -0.1084 | -0.1686 | -0.1660 | -0.1939 | -0.0275 | -0.0031 | -0.0253 | 0.0226 |
| D8 | 0.0243 | -0.1429 | 0.0570 | -0.0481 | 0.1643 | -0.2036 | 0.1171 | -0.1493 | -0.2962 | -0.0528 | 0.3444 | -0.0122 | -0.1169 | 0.0358 | 0.0750 | 0.0514 | 0.1374 | 0.1362 | -0.0570 | 0.0380 | 0.0996 | 0.2868 | -0.0523 | -0.1583 | -0.0696 | 0.0879 | 0.2654 | 0.0352 | 0.1383 | 0.0823 | 0.1527 | 0.2735 | 0.0441 | -0.0019 | -0.2130 | 0.0653 | 0.0677 | -0.0194 | 0.0126 | -0.0893 | 0.1386 | -0.0167 | -0.0298 | -0.0038 | -0.0018 | -0.1625 | 0.0163 | 0.0174 | -0.0134 | 0.0101 | -0.0265 | 0.0199 | -0.0468 | 0.0103 | -0.0590 | -0.0650 | 0.1348 | 0.0038 | 0.1583 | 0.1026 | 0.1238 | 0.0223 | 0.0339 | -0.1923 | -0.1860 | -0.0221 | 0.0205 |
| D9 | 0.0227 | -0.0648 | -0.0822 | 0.0694 | 0.0612 | 0.0148 | -0.0317 | 0.0081 | -0.0999 | -0.1275 | 0.2397 | 0.0683 | -0.0750 | 0.5776 | -0.0246 | 0.0020 | 0.0525 | 0.0487 | 0.0593 | -0.0032 | -0.0711 | -0.2318 | -0.0349 | -0.1723 | -0.0608 | -0.0051 | -0.1022 | 0.1148 | 0.1291 | -0.0328 | -0.0249 | -0.0495 | -0.0826 | -0.0072 | 0.4615 | 0.0954 | -0.0278 | 0.0537 | 0.0045 | -0.1002 | -0.0373 | 0.1199 | 0.1434 | -0.0356 | -0.0664 | -0.0667 | -0.0431 | -0.0060 | 0.0020 | -0.0391 | 0.0164 | -0.1275 | -0.1315 | -0.0126 | 0.0282 | -0.1746 | 0.0006 | 0.0465 | -0.0161 | -0.0272 | -0.1003 | -0.0422 | -0.1175 | -0.1044 | 0.0638 | 0.0522 | 0.0138 |
| D10 | 0.0218 | 0.1167 | -0.0474 | 0.0944 | 0.1003 | 0.0331 | -0.1702 | 0.0106 | 0.0560 | -0.2760 | 0.1398 | 0.0703 | -0.0254 | 0.0123 | -0.1387 | 0.1093 | -0.0672 | -0.0484 | -0.0329 | -0.0054 | -0.1427 | 0.0860 | 0.1177 | -0.0489 | 0.0637 | -0.0546 | -0.0838 | 0.0654 | -0.0205 | -0.0110 | -0.1368 | -0.0645 | 0.2367 | -0.0108 | -0.2411 | 0.0454 | -0.1698 | -0.0535 | -0.0701 | -0.0902 | -0.3362 | -0.0060 | -0.0335 | -0.0580 | 0.5009 | -0.1767 | 0.0942 | -0.0508 | -0.0017 | -0.0197 | -0.0225 | -0.1053 | -0.0230 | -0.0640 | 0.1565 | -0.0193 | 0.0905 | 0.0849 | 0.1550 | 0.0010 | 0.0372 | 0.0071 | -0.0342 | -0.0555 | 0.1065 | -0.0798 | -0.1701 |
| D11 | 0.0211 | -0.0256 | 0.0073 | -0.0124 | 0.0936 | -0.0802 | 0.1413 | -0.1423 | 0.0568 | -0.1870 | -0.1016 | -0.0873 | -0.0945 | -0.0066 | 0.0062 | 0.0552 | 0.0574 | 0.1427 | -0.0422 | 0.0204 | 0.0433 | 0.0966 | -0.0015 | -0.0409 | -0.0047 | 0.0380 | 0.0986 | 0.0693 | 0.0093 | 0.0492 | 0.0787 | 0.0653 | 0.0471 | 0.0033 | -0.0851 | -0.0178 | 0.0105 | 0.0850 | -0.0558 | -0.0129 | -0.0062 | 0.1597 | 0.1910 | -0.0686 | 0.1468 | 0.4355 | -0.0185 | -0.0734 | -0.1495 | 0.0543 | -0.0842 | -0.1455 | 0.1171 | -0.0494 | -0.0141 | 0.2133 | -0.1301 | 0.0325 | -0.1901 | -0.1693 | -0.4503 | -0.0237 | -0.2677 | -0.1007 | -0.0563 | 0.0398 | -0.1256 |
| D12 | 0.0200 | -0.0184 | -0.0011 | 0.0094 | -0.0486 | 0.0040 | -0.0478 | 0.0703 | -0.0222 | 0.0753 | 0.0104 | -0.0299 | -0.1134 | -0.0727 | -0.0260 | -0.0608 | -0.0363 | -0.0402 | 0.0294 | -0.0219 | 0.0078 | -0.0622 | 0.0350 | -0.0147 | -0.0027 | 0.0267 | -0.0178 | -0.0181 | -0.0625 | 0.0228 | -0.0070 | -0.0173 | 0.0259 | 0.0071 | -0.0463 | -0.0101 | -0.0309 | 0.2314 | -0.0491 | 0.0580 | -0.0699 | 0.2431 | 0.3824 | 0.1164 | 0.1183 | -0.2476 | -0.3234 | -0.0789 | -0.1615 | 0.0535 | -0.1294 | 0.0756 | 0.2101 | -0.0214 | 0.0604 | 0.2028 | 0.0818 | -0.0251 | 0.0852 | 0.0343 | 0.1143 | 0.1020 | -0.0576 | -0.1181 | -0.0084 | 0.2947 | 0.4326 |
| D13 | 0.0188 | -0.0116 | 0.0290 | -0.0238 | 0.0838 | 0.0075 | -0.0354 | 0.0742 | -0.0166 | -0.1020 | 0.0575 | -0.0248 | 0.2257 | 0.0209 | -0.0634 | 0.1566 | -0.0498 | -0.0036 | -0.0331 | 0.0080 | 0.0519 | 0.0389 | -0.0488 | 0.0298 | 0.0235 | 0.0269 | 0.0528 | 0.0323 | 0.0299 | 0.0177 | 0.0711 | 0.0113 | -0.0376 | 0.0013 | 0.0166 | -0.0283 | -0.0456 | 0.4568 | -0.0290 | 0.0666 | 0.0908 | 0.1722 | 0.4533 | 0.0158 | -0.0155 | -0.0176 | 0.2308 | 0.0761 | 0.2267 | -0.0982 | 0.1648 | -0.0074 | 0.1287 | 0.0494 | -0.1075 | 0.1231 | 0.0255 | -0.0137 | 0.0552 | 0.0498 | 0.1305 | -0.0639 | 0.1533 | 0.2568 | 0.0286 | -0.2184 | -0.2154 |
| D14 | 0.0164 | 0.0115 | -0.0528 | -0.0316 | -0.0301 | -0.0358 | 0.1120 | -0.1732 | 0.0920 | -0.0441 | -0.1748 | 0.0639 | -0.0871 | 0.0569 | 0.0469 | -0.0838 | 0.2206 | -0.0010 | 0.0175 | 0.0071 | -0.0914 | 0.0048 | 0.0820 | -0.1700 | -0.0330 | -0.0264 | -0.0557 | -0.0078 | 0.0313 | -0.0278 | -0.0909 | 0.0088 | 0.1595 | 0.0140 | -0.0488 | 0.0802 | 0.0244 | 0.1680 | 0.1028 | -0.1366 | -0.1777 | 0.0138 | 0.1561 | 0.1545 | 0.0927 | 0.3541 | -0.0071 | -0.0843 | 0.0870 | 0.0541 | 0.0994 | 0.2988 | -0.1669 | -0.0746 | 0.0443 | -0.2099 | -0.0794 | -0.1998 | -0.0791 | 0.0480 | 0.1558 | 0.0279 | 0.4102 | -0.1374 | -0.0401 | -0.0105 | 0.0816 |
| D15 | 0.0152 | -0.0548 | 0.0506 | 0.1380 | 0.0129 | -0.1121 | 0.1852 | -0.0612 | -0.1346 | 0.1368 | -0.0025 | 0.5213 | 0.0482 | -0.1058 | 0.0201 | -0.0108 | -0.0697 | 0.0031 | -0.0742 | -0.0062 | 0.0703 | -0.0181 | -0.0696 | -0.0287 | -0.0264 | -0.0182 | 0.0605 | -0.0074 | -0.0328 | 0.0092 | 0.0580 | 0.0207 | -0.2575 | 0.5220 | 0.1272 | -0.1480 | 0.0382 | 0.0303 | -0.0371 | 0.0570 | -0.3274 | 0.0130 | -0.0171 | 0.0356 | 0.1004 | -0.0088 | 0.0349 | -0.0178 | 0.0112 | -0.0101 | 0.0138 | 0.0319 | 0.0395 | -0.0241 | 0.1973 | 0.0109 | -0.0041 | -0.0151 | -0.0058 | -0.0155 | -0.0217 | -0.0063 | -0.0434 | 0.0590 | -0.1159 | -0.0306 | -0.0560 |
| D16 | 0.0151 | 0.0251 | -0.0282 | -0.0957 | -0.0060 | 0.0689 | -0.1151 | 0.0406 | 0.0851 | -0.0875 | 0.0003 | -0.3275 | -0.0351 | 0.0711 | -0.0229 | 0.0119 | 0.0351 | 0.0025 | 0.0460 | 0.0026 | -0.0400 | 0.0056 | 0.0393 | 0.0074 | 0.0109 | 0.0074 | -0.0331 | 0.0102 | 0.0213 | -0.0039 | -0.0325 | -0.0127 | 0.1499 | 0.8506 | -0.0630 | 0.0491 | -0.0333 | -0.0417 | 0.0135 | -0.0266 | 0.2115 | -0.0009 | 0.0026 | -0.0244 | -0.0324 | -0.0046 | -0.0161 | 0.0010 | 0.0032 | 0.0042 | -0.0054 | -0.0259 | -0.0274 | 0.0069 | -0.1312 | -0.0124 | 0.0051 | 0.0176 | 0.0117 | 0.0054 | 0.0178 | 0.0016 | 0.0291 | -0.0396 | 0.0705 | 0.0140 | 0.0305 |
| D17 | 0.0148 | 0.0919 | -0.0257 | 0.4283 | 0.0461 | -0.0093 | -0.0145 | -0.0544 | -0.0554 | -0.0368 | 0.1630 | -0.0183 | -0.1073 | -0.0108 | -0.0840 | -0.0071 | -0.2188 | -0.1829 | 0.0191 | 0.0023 | -0.0236 | 0.0908 | 0.0077 | 0.2016 | 0.0780 | 0.0506 | -0.0234 | -0.0146 | 0.0382 | -0.0028 | 0.0334 | -0.0203 | 0.0889 | 0.0399 | -0.1866 | 0.1989 | -0.0874 | 0.1256 | 0.1185 | -0.0057 | -0.1673 | -0.0718 | 0.0760 | -0.1120 | -0.4878 | 0.1653 | -0.0251 | 0.2018 | -0.0448 | 0.0313 | 0.0082 | -0.0982 | -0.0228 | 0.1481 | 0.2401 | 0.0321 | -0.0258 | -0.0316 | -0.0549 | 0.0612 | -0.0187 | 0.0299 | 0.0578 | -0.1432 | 0.0189 | 0.0248 | 0.0235 |
| D18 | 0.0144 | -0.0526 | 0.0239 | -0.2260 | 0.0174 | -0.0322 | 0.0230 | -0.0202 | 0.0185 | 0.0809 | -0.1040 | -0.2384 | -0.1532 | -0.0845 | 0.0592 | 0.0110 | 0.3382 | -0.1857 | -0.0265 | -0.0508 | -0.0293 | -0.1288 | -0.0199 | -0.0620 | -0.0675 | -0.0362 | -0.0128 | -0.0230 | -0.0452 | -0.0216 | -0.0659 | 0.0104 | -0.1373 | 0.0000 | 0.0660 | -0.1266 | 0.0621 | 0.3697 | -0.0465 | 0.1047 | -0.2292 | -0.2934 | -0.0465 | -0.2363 | 0.0419 | -0.0769 | 0.0095 | 0.2349 | -0.0250 | 0.0086 | -0.0342 | -0.2703 | -0.0218 | 0.1684 | 0.0908 | 0.0210 | 0.0040 | 0.1113 | 0.0572 | 0.0114 | 0.0429 | 0.0154 | 0.0338 | -0.2153 | -0.0754 | -0.0020 | -0.1057 |
| D19 | 0.0142 | 0.0543 | -0.0144 | 0.0888 | -0.0266 | 0.0394 | -0.0255 | -0.0096 | 0.0740 | -0.0479 | -0.0148 | -0.1495 | -0.2231 | -0.0717 | 0.0430 | -0.0815 | -0.5345 | 0.2567 | -0.1552 | 0.0534 | 0.0658 | 0.1654 | -0.0225 | 0.0908 | 0.0175 | -0.0433 | 0.0365 | 0.0709 | -0.0250 | 0.0023 | -0.0006 | -0.0210 | -0.3135 | -0.0078 | 0.1931 | 0.0281 | 0.0292 | 0.3118 | 0.0032 | -0.1041 | 0.1306 | -0.2110 | -0.0632 | 0.0002 | 0.2586 | 0.0206 | -0.0286 | -0.0135 | -0.0333 | 0.0489 | -0.0721 | 0.0548 | -0.1365 | -0.0250 | -0.0734 | -0.1316 | -0.0208 | -0.0316 | 0.0045 | 0.0151 | 0.0545 | 0.0073 | 0.0687 | -0.1288 | 0.0571 | 0.0262 | -0.0280 |
| D20 | 0.0140 | 0.0622 | -0.0376 | -0.1388 | -0.0454 | 0.0683 | -0.0980 | 0.0574 | 0.0314 | -0.0072 | 0.0300 | 0.5218 | 0.0509 | 0.0626 | -0.0018 | -0.0459 | 0.1449 | 0.1096 | 0.0632 | 0.0124 | -0.0479 | 0.0214 | 0.0599 | 0.0444 | 0.0492 | 0.0216 | -0.0528 | -0.0129 | 0.0031 | -0.0055 | -0.0378 | -0.0265 | 0.2195 | 0.0268 | -0.1341 | 0.1730 | 0.0029 | 0.4832 | 0.0472 | -0.0844 | 0.2105 | -0.2749 | -0.1745 | 0.0091 | -0.0804 | -0.0526 | -0.0522 | 0.0131 | -0.1265 | 0.0329 | -0.1101 | 0.0748 | 0.0422 | 0.0091 | -0.1509 | 0.0025 | 0.0013 | 0.0074 | -0.0326 | -0.0080 | -0.1068 | 0.0112 | -0.1890 | 0.0470 | 0.0511 | 0.0583 | -0.0359 |
| D21 | 0.0130 | 0.0492 | 0.0007 | 0.4089 | -0.0297 | 0.0020 | 0.0127 | 0.0012 | -0.0617 | 0.0709 | 0.0969 | -0.3455 | 0.0761 | -0.0849 | -0.0608 | -0.0313 | 0.4425 | 0.0653 | -0.0426 | 0.0088 | 0.0108 | 0.0527 | -0.0231 | 0.1215 | 0.0212 | -0.0329 | -0.0296 | 0.0395 | -0.0252 | -0.0185 | -0.0048 | -0.0354 | -0.1038 | 0.0111 | 0.0970 | 0.0577 | -0.0608 | 0.1556 | 0.0548 | 0.0408 | -0.0448 | -0.0288 | -0.0654 | 0.2211 | 0.0536 | -0.1241 | 0.1106 | -0.0735 | -0.1404 | 0.0088 | -0.1005 | 0.3647 | -0.0637 | -0.0565 | 0.0916 | -0.0598 | 0.0276 | -0.0716 | -0.0228 | -0.0054 | -0.0889 | 0.0114 | -0.2616 | 0.1200 | 0.0117 | -0.1125 | -0.0858 |
| D22 | 0.0129 | -0.1466 | 0.0223 | -0.0845 | -0.0397 | -0.0531 | 0.0881 | -0.0306 | -0.0617 | 0.1365 | -0.0542 | -0.1938 | 0.0529 | 0.1934 | -0.0135 | -0.0401 | -0.4521 | -0.1793 | 0.1749 | -0.0434 | -0.0414 | -0.1574 | 0.0018 | -0.2776 | -0.1056 | 0.0187 | 0.0278 | -0.1045 | 0.0601 | 0.0196 | 0.0231 | 0.0505 | 0.2740 | -0.0079 | -0.1249 | -0.2293 | 0.0017 | 0.1861 | -0.0614 | 0.1231 | -0.0733 | -0.0720 | -0.0859 | 0.1273 | -0.0829 | -0.0530 | 0.1275 | -0.0829 | -0.0909 | 0.0146 | -0.0633 | 0.2779 | -0.0316 | -0.0489 | 0.0944 | -0.0339 | 0.0330 | 0.0165 | 0.0070 | -0.0290 | -0.0925 | 0.0251 | -0.1777 | -0.0348 | -0.0864 | -0.1224 | -0.1278 |
| D23 | 0.0124 | 0.0527 | 0.0052 | -0.4052 | 0.0133 | 0.0933 | -0.1342 | 0.0438 | 0.0242 | -0.1128 | 0.1055 | 0.0781 | -0.0749 | -0.1460 | 0.0208 | 0.0535 | -0.0457 | -0.0394 | -0.0849 | -0.0407 | -0.0230 | -0.0138 | -0.0224 | -0.0237 | 0.0100 | -0.0270 | -0.0338 | -0.0447 | -0.0246 | -0.0013 | -0.0857 | -0.0254 | -0.2635 | 0.0081 | -0.0633 | 0.0464 | -0.0040 | -0.1823 | 0.0306 | -0.1360 | -0.1445 | 0.1496 | 0.2390 | 0.1834 | -0.1948 | -0.0063 | 0.1135 | 0.2088 | -0.3012 | 0.0725 | -0.2135 | 0.2271 | -0.0712 | 0.1739 | -0.0682 | -0.1147 | 0.0204 | -0.0996 | -0.0230 | 0.0657 | -0.0174 | 0.0849 | -0.1172 | -0.1035 | 0.0834 | -0.0863 | -0.2280 |
| D24 | 0.0116 | -0.0160 | 0.0235 | 0.3347 | 0.0407 | 0.0011 | 0.0026 | -0.0100 | 0.0452 | -0.0497 | -0.0999 | 0.2253 | -0.1835 | -0.0252 | -0.1292 | 0.0299 | 0.0969 | -0.2737 | 0.0011 | -0.0333 | -0.0410 | -0.1115 | 0.0043 | -0.0813 | -0.0123 | -0.0512 | -0.0319 | -0.0197 | -0.0343 | -0.0010 | -0.0466 | -0.0384 | -0.0780 | -0.0186 | -0.0795 | -0.2856 | -0.1068 | -0.0693 | -0.1197 | 0.1393 | 0.5769 | 0.0409 | 0.1250 | 0.0377 | 0.1071 | 0.0090 | 0.0066 | 0.0597 | -0.1112 | 0.0144 | -0.0374 | 0.0182 | -0.0933 | 0.0644 | 0.0163 | -0.0829 | 0.0033 | 0.0268 | 0.0248 | 0.0112 | 0.0520 | 0.0518 | 0.0714 | -0.2176 | -0.0470 | 0.0238 | -0.2142 |
| D25 | 0.0110 | 0.0066 | -0.0300 | -0.0103 | -0.0059 | 0.0380 | -0.0578 | 0.0220 | 0.0821 | 0.0446 | -0.1242 | 0.0812 | -0.1802 | 0.1541 | 0.0434 | -0.0320 | 0.0550 | 0.2530 | 0.1145 | 0.0889 | 0.0542 | 0.2198 | -0.0041 | 0.4248 | 0.0765 | 0.0331 | 0.0619 | 0.0108 | 0.0547 | 0.0219 | 0.0959 | 0.0349 | 0.4126 | -0.0101 | 0.2566 | -0.3714 | 0.0790 | -0.1020 | -0.0762 | 0.1302 | -0.1371 | 0.0072 | 0.1268 | 0.0356 | -0.0037 | -0.0981 | 0.0430 | 0.1764 | -0.0145 | 0.0152 | -0.0749 | 0.0793 | -0.0721 | 0.1332 | -0.0088 | 0.0147 | -0.0104 | -0.0359 | 0.0019 | 0.0358 | 0.0719 | -0.0427 | -0.0052 | -0.1116 | -0.0280 | -0.0384 | -0.0831 |
| D26 | 0.0104 | 0.0167 | -0.0465 | -0.1633 | 0.0520 | -0.1017 | 0.0688 | -0.1814 | -0.0040 | 0.0890 | -0.1711 | 0.0224 | 0.0548 | 0.0651 | 0.0952 | 0.0493 | -0.0840 | -0.4727 | 0.0135 | 0.0828 | -0.0070 | 0.1548 | 0.0764 | 0.2472 | 0.0097 | 0.0029 | 0.0334 | 0.1617 | 0.0258 | -0.0321 | -0.0309 | 0.1589 | 0.0629 | 0.0134 | 0.2543 | 0.5147 | 0.0849 | -0.0481 | -0.0599 | 0.1402 | 0.1315 | 0.0140 | 0.0409 | 0.0651 | 0.1831 | -0.0706 | 0.0024 | 0.0104 | -0.0671 | -0.0188 | 0.0175 | 0.0613 | -0.0194 | 0.0092 | 0.1301 | 0.0413 | 0.0005 | 0.0001 | 0.0091 | -0.0078 | 0.0198 | 0.0418 | -0.0702 | -0.0009 | -0.0750 | 0.0090 | -0.1029 |
| D27 | 0.0097 | -0.0918 | 0.0219 | 0.2139 | -0.0550 | -0.0666 | 0.1003 | -0.0027 | -0.0171 | 0.1762 | -0.2242 | -0.0244 | 0.0303 | -0.1376 | 0.0263 | -0.0360 | -0.0653 | 0.3883 | 0.0784 | -0.0302 | 0.0413 | -0.2880 | 0.0245 | -0.2243 | -0.0826 | -0.0003 | -0.0307 | -0.0410 | -0.0889 | -0.0175 | 0.0524 | 0.0034 | 0.2055 | 0.0117 | -0.0250 | 0.3906 | 0.0235 | -0.1357 | 0.0200 | -0.0512 | 0.0242 | -0.0680 | 0.2063 | 0.0299 | 0.1226 | -0.1352 | 0.0113 | 0.2782 | -0.0107 | -0.0111 | -0.0823 | -0.1422 | 0.0052 | 0.2139 | -0.0203 | -0.0599 | -0.0068 | -0.0545 | -0.0128 | 0.0631 | 0.0385 | -0.0203 | -0.0370 | 0.0507 | -0.0564 | 0.0122 | -0.1878 |
| D28 | 0.0094 | 0.1062 | -0.0434 | 0.0201 | -0.0986 | -0.0015 | 0.0582 | 0.0151 | -0.0005 | 0.1930 | -0.2095 | -0.0459 | 0.0547 | 0.5935 | 0.0705 | -0.1189 | 0.0352 | 0.0960 | -0.2060 | 0.0318 | -0.0419 | 0.1735 | 0.0027 | 0.0634 | 0.0142 | 0.0223 | -0.0305 | 0.0024 | 0.0504 | -0.0436 | -0.0921 | -0.0890 | -0.2836 | 0.0057 | -0.4614 | 0.0006 | 0.0868 | -0.0298 | -0.0422 | 0.0843 | -0.0454 | 0.0426 | 0.0153 | 0.0718 | 0.0285 | -0.0646 | -0.0763 | 0.0544 | -0.0236 | -0.0401 | -0.0338 | -0.0699 | 0.0020 | 0.0411 | 0.0222 | 0.0714 | -0.0093 | -0.0324 | -0.0202 | 0.0265 | 0.0760 | 0.0124 | 0.0119 | 0.0826 | -0.0333 | 0.1040 | -0.1643 |
| D29 | 0.0083 | 0.0151 | 0.0034 | 0.0138 | 0.0599 | -0.0249 | -0.0504 | -0.0478 | 0.0784 | -0.0188 | -0.1494 | 0.0560 | -0.0097 | 0.0691 | 0.0103 | 0.0911 | 0.0121 | 0.0895 | 0.0295 | -0.0195 | -0.0242 | 0.0181 | 0.0127 | -0.0150 | -0.0135 | 0.0034 | 0.0069 | 0.0352 | 0.0354 | 0.0302 | -0.0794 | -0.0084 | -0.1504 | -0.0001 | -0.0910 | 0.0647 | -0.0148 | -0.1506 | -0.0135 | 0.0091 | 0.0335 | -0.2732 | 0.2961 | -0.3759 | -0.0448 | -0.0586 | 0.0571 | 0.0384 | 0.2878 | 0.0903 | -0.0519 | 0.4627 | 0.0181 | 0.0260 | 0.0796 | -0.0022 | -0.0019 | 0.3355 | 0.1210 | -0.1444 | -0.1192 | -0.0239 | -0.1105 | -0.0428 | -0.0217 | -0.0917 | 0.2248 |
| D30 | 0.0082 | -0.0055 | -0.0255 | 0.0505 | -0.0273 | -0.0132 | 0.0167 | -0.0145 | 0.0151 | 0.0261 | -0.0137 | 0.0396 | 0.0546 | 0.1091 | 0.0239 | -0.0335 | -0.0241 | -0.1277 | -0.1432 | -0.0094 | -0.0246 | 0.1058 | 0.0112 | -0.0857 | -0.0433 | -0.0009 | -0.0186 | -0.0293 | 0.0108 | -0.0541 | -0.0179 | -0.0551 | 0.0353 | 0.0001 | 0.0098 | -0.0911 | 0.0136 | -0.0684 | 0.1350 | -0.0155 | 0.0699 | -0.1672 | 0.1333 | -0.1924 | 0.1708 | -0.0094 | 0.2730 | 0.1183 | -0.2868 | -0.0332 | 0.0116 | -0.1505 | 0.0313 | 0.0372 | -0.0824 | -0.0021 | -0.0143 | -0.3676 | -0.1500 | 0.1021 | 0.0185 | 0.0038 | -0.1425 | 0.0686 | -0.0240 | -0.3701 | 0.4743 |
| D31 | 0.0075 | -0.0072 | -0.0117 | -0.0175 | -0.1649 | 0.0511 | 0.0906 | 0.1158 | -0.0994 | 0.1342 | 0.4080 | -0.0406 | 0.0835 | -0.0289 | 0.0135 | -0.2363 | 0.0014 | -0.1572 | -0.0749 | 0.0333 | -0.0400 | 0.1026 | -0.0085 | -0.0509 | -0.0220 | -0.0272 | -0.0215 | -0.0973 | -0.0091 | -0.0339 | 0.0033 | -0.0337 | 0.1146 | 0.0013 | 0.0838 | -0.0708 | 0.0342 | -0.1519 | 0.0586 | 0.0159 | -0.0167 | -0.3170 | 0.2981 | -0.2477 | 0.1488 | 0.0929 | -0.2011 | -0.0226 | 0.0201 | 0.0408 | 0.0632 | 0.1280 | 0.0185 | -0.0672 | -0.1194 | 0.0859 | -0.0643 | -0.1209 | -0.0619 | 0.0488 | -0.0487 | 0.0508 | 0.0251 | 0.1010 | 0.0470 | 0.2471 | -0.3156 |
| D32 | 0.0073 | 0.0496 | 0.0850 | -0.0097 | -0.0602 | -0.0059 | -0.0236 | 0.0068 | -0.0076 | 0.0520 | 0.0215 | -0.0143 | 0.0353 | -0.0273 | 0.0240 | -0.0525 | 0.0069 | 0.0184 | 0.7802 | 0.0211 | -0.0584 | 0.1514 | 0.0240 | -0.0660 | 0.1375 | -0.0843 | -0.0042 | 0.3978 | 0.0400 | 0.1239 | -0.0049 | -0.0463 | -0.2441 | -0.0019 | -0.0925 | -0.0577 | -0.0030 | -0.0296 | 0.0035 | -0.0661 | -0.0092 | -0.0994 | 0.0679 | 0.0163 | 0.0431 | -0.0025 | 0.0059 | 0.0190 | -0.0660 | -0.0135 | 0.0602 | -0.0814 | 0.0309 | -0.0231 | 0.0146 | 0.0093 | -0.0010 | -0.1240 | -0.0479 | 0.0411 | 0.0046 | -0.0073 | 0.0113 | 0.0108 | -0.0483 | -0.0069 | -0.0237 |
| D33 | 0.0070 | -0.1243 | 0.0799 | -0.0423 | 0.0077 | 0.0794 | -0.0024 | 0.0898 | -0.0009 | -0.1293 | 0.2293 | 0.0410 | -0.0803 | 0.0393 | 0.1273 | 0.0564 | 0.0028 | 0.0529 | 0.1136 | -0.0407 | 0.1159 | -0.3440 | -0.1410 | 0.2714 | -0.1325 | -0.0365 | -0.0650 | 0.0494 | -0.0552 | -0.0161 | 0.2435 | -0.1194 | -0.0390 | 0.0014 | -0.2617 | 0.1728 | 0.2399 | 0.0121 | -0.0458 | 0.4197 | -0.0279 | 0.0447 | -0.0343 | -0.1326 | 0.1710 | 0.0943 | 0.0378 | -0.0578 | -0.0762 | -0.0253 | -0.0107 | 0.1114 | -0.2457 | -0.0458 | -0.0075 | 0.0261 | -0.0134 | -0.0895 | -0.0312 | 0.0135 | 0.0121 | -0.0770 | 0.0852 | -0.0359 | 0.0608 | -0.0620 | 0.0683 |
| D34 | 0.0065 | 0.0342 | -0.0550 | 0.0337 | -0.0057 | 0.0548 | -0.1433 | 0.0441 | 0.0917 | -0.0128 | 0.0525 | 0.0307 | 0.0229 | -0.1240 | 0.0633 | 0.0172 | -0.0111 | 0.1976 | -0.0699 | -0.0708 | -0.1683 | 0.2054 | 0.1227 | -0.3069 | -0.0638 | -0.0306 | -0.0115 | 0.1238 | 0.0366 | -0.0003 | -0.3058 | 0.1110 | 0.0177 | 0.0027 | 0.1029 | 0.0526 | 0.1740 | 0.0395 | -0.1284 | 0.4258 | 0.0524 | 0.2177 | -0.1218 | -0.2518 | -0.1609 | -0.0724 | -0.0070 | -0.0450 | 0.1086 | 0.0615 | -0.0700 | 0.0533 | 0.0259 | -0.0070 | 0.1737 | 0.0599 | -0.0490 | -0.2864 | -0.1050 | 0.0962 | 0.0154 | -0.0356 | -0.0208 | -0.0653 | 0.0203 | 0.0068 | -0.0784 |
| D35 | 0.0065 | 0.0066 | 0.0116 | 0.0018 | 0.0027 | -0.0448 | 0.0626 | 0.0078 | -0.0832 | 0.0537 | -0.1335 | -0.0294 | -0.0270 | 0.0312 | -0.0490 | 0.0212 | -0.0077 | -0.0618 | 0.0580 | 0.0541 | 0.0676 | -0.0729 | 0.0009 | 0.0721 | 0.0478 | 0.0181 | -0.0030 | -0.0238 | -0.0031 | 0.0222 | 0.1055 | -0.0320 | -0.0039 | -0.0013 | -0.0179 | -0.0156 | -0.1384 | 0.1009 | -0.0038 | -0.3102 | -0.0123 | 0.4199 | -0.2476 | -0.5662 | 0.0923 | -0.1163 | -0.0626 | 0.1364 | -0.0865 | -0.0133 | 0.1411 | 0.2925 | 0.0222 | 0.0899 | -0.0902 | -0.0272 | -0.0252 | -0.1807 | -0.0827 | 0.0165 | 0.0246 | 0.0208 | -0.0103 | 0.0109 | -0.0327 | 0.0769 | -0.1070 |
| D36 | 0.0064 | 0.0476 | -0.0145 | 0.1445 | -0.0987 | 0.0531 | 0.0620 | 0.0551 | -0.0083 | 0.0340 | 0.1437 | 0.0214 | 0.0095 | -0.0270 | 0.1025 | -0.1449 | -0.0268 | -0.1644 | 0.0187 | 0.0663 | -0.0434 | 0.1761 | 0.0142 | -0.2015 | 0.0229 | -0.0260 | -0.0657 | 0.1155 | 0.0105 | -0.0439 | -0.0017 | -0.1128 | 0.0526 | 0.0005 | 0.0230 | 0.0019 | 0.1937 | 0.0514 | 0.0583 | 0.1402 | -0.0770 | 0.2612 | -0.1627 | 0.1127 | 0.1593 | 0.1613 | 0.0195 | 0.4080 | 0.1154 | 0.0675 | -0.0613 | 0.0759 | -0.0047 | 0.2290 | -0.3434 | -0.0304 | 0.0341 | 0.2991 | 0.1285 | -0.1193 | -0.1134 | 0.0671 | 0.0135 | 0.0464 | -0.0022 | -0.0298 | 0.1547 |
| D37 | 0.0061 | 0.0397 | -0.0404 | 0.1501 | 0.0943 | -0.0003 | -0.0588 | -0.0145 | 0.0559 | -0.0545 | -0.1350 | 0.0139 | -0.0348 | -0.0611 | 0.1136 | 0.1209 | -0.0199 | 0.0379 | -0.1009 | -0.0134 | 0.0403 | 0.0396 | 0.0096 | -0.1424 | -0.0207 | 0.0488 | -0.0082 | 0.2150 | -0.0092 | -0.0955 | -0.0191 | -0.0439 | 0.0513 | 0.0024 | 0.0204 | -0.0002 | 0.1465 | -0.0328 | -0.0580 | 0.0962 | -0.1616 | -0.1162 | 0.0665 | -0.0517 | -0.1810 | -0.0868 | -0.0491 | -0.1323 | -0.4885 | -0.1968 | 0.4591 | 0.0903 | 0.0293 | -0.0575 | -0.2935 | -0.0249 | 0.0908 | 0.1983 | 0.0071 | -0.0941 | 0.0754 | -0.0106 | 0.0515 | 0.0029 | -0.0260 | 0.0683 | -0.0759 |
| D38 | 0.0057 | 0.0144 | 0.0310 | 0.2361 | 0.1138 | -0.0515 | -0.1373 | -0.1339 | 0.0330 | -0.1308 | -0.1483 | 0.0180 | -0.0368 | 0.0223 | 0.1147 | 0.1392 | -0.0098 | -0.1795 | 0.1189 | 0.0001 | -0.0344 | -0.0764 | 0.0056 | 0.0161 | 0.1260 | -0.0232 | 0.0649 | -0.3120 | 0.1208 | 0.1420 | -0.0235 | 0.0761 | -0.1019 | 0.0017 | -0.0007 | 0.0359 | 0.1582 | -0.0077 | 0.0451 | 0.0563 | -0.2109 | -0.0515 | 0.0223 | 0.0019 | -0.0189 | -0.1136 | -0.0379 | -0.1389 | 0.2249 | 0.0992 | -0.1521 | -0.0651 | -0.0150 | -0.0892 | -0.5310 | -0.0035 | -0.0859 | -0.1942 | -0.0218 | 0.0971 | 0.0438 | 0.0864 | -0.1614 | -0.0476 | -0.0327 | 0.0525 | -0.0702 |
| D39 | 0.0056 | 0.0027 | 0.0586 | -0.0130 | -0.0682 | 0.0267 | -0.0051 | 0.0582 | -0.0364 | -0.0601 | 0.0291 | -0.0044 | 0.0314 | 0.0612 | -0.0740 | -0.0284 | 0.0105 | 0.1460 | 0.2078 | -0.1124 | -0.1659 | 0.0955 | -0.0155 | 0.0220 | 0.1633 | -0.1088 | 0.1457 | -0.6375 | 0.1392 | 0.1327 | -0.1352 | 0.1306 | -0.1123 | 0.0033 | 0.0880 | 0.1364 | 0.0088 | 0.0102 | 0.0185 | 0.1493 | 0.0428 | 0.0390 | -0.0271 | 0.0057 | 0.1393 | 0.0716 | 0.0120 | 0.1031 | -0.2530 | -0.0299 | 0.2974 | 0.0281 | 0.0128 | 0.0597 | 0.1221 | 0.0284 | 0.0643 | 0.1270 | 0.0231 | -0.0881 | -0.0458 | -0.0198 | 0.0882 | -0.0120 | 0.0370 | -0.0184 | 0.0472 |
| D40 | 0.0050 | 0.0288 | -0.0656 | -0.0046 | -0.0866 | -0.0202 | -0.1489 | -0.2078 | 0.1430 | 0.0670 | 0.1632 | 0.0036 | 0.0040 | -0.0576 | 0.0049 | -0.2518 | -0.0057 | 0.0760 | -0.1046 | 0.1867 | 0.0022 | -0.3574 | 0.2064 | 0.1358 | 0.0554 | 0.1396 | -0.0363 | 0.1329 | 0.2283 | 0.0772 | -0.0552 | 0.3120 | -0.0728 | -0.0014 | -0.1088 | -0.0850 | 0.0106 | -0.0022 | -0.1294 | 0.0010 | 0.0115 | -0.0007 | 0.0012 | 0.0803 | 0.0498 | -0.0365 | 0.0580 | 0.0756 | 0.0652 | 0.2157 | 0.3938 | -0.0205 | 0.0511 | 0.0756 | 0.0004 | -0.0031 | -0.0348 | -0.0653 | 0.0283 | -0.0209 | -0.0882 | 0.2402 | -0.0983 | -0.0190 | 0.0179 | -0.0661 | 0.0252 |
# Map weights for the second principal component to corresponding feature names
# and then print the linked values, sorted by weight.
def pca_weights(full_dataset, pca, comp):
""" Print the sorted list of feature weights, for the i-th principal component"""
# Dimension indexing
dimensions = ['D{}'.format(i) for i in range(1,len(pca.components_)+1)]
# PCA components
components = pd.DataFrame(np.round(pca.components_, 4), columns = full_dataset.keys())
components.index = dimensions
# PCA explained variance
ratios = pca.explained_variance_ratio_.reshape(len(pca.components_), 1)
variance_ratios = pd.DataFrame(np.round(ratios, 4), columns=['Explained Variance'])
variance_ratios.index = dimensions
# PCA results as dataframe
results = pd.concat([variance_ratios, components], axis=1)
results = results.drop('Explained Variance', axis=1)
results = results.transpose()
# Single out desired i-th principal component
key = 'D'+str(comp)
result = pd.DataFrame(results[key].sort_values(ascending=False))
return result
# Map weights for the third principal component to corresponding feature names
# and then print the linked values, sorted by weight.
comp = 1
result = pca_weights(df_impute, pca_40, comp)
result.head()
| D1 | |
|---|---|
| FINANZ_SPARER | 0.2280 |
| SEMIO_PFLICHT | 0.1933 |
| SEMIO_REL | 0.1918 |
| DACADE | 0.1893 |
| HH_EINKOMMEN_SCORE | 0.1834 |
Positive weights
Negative weights
result.tail()
| D1 | |
|---|---|
| MOBI_REGIO | -0.1886 |
| FINANZ_VORSORGER | -0.1929 |
| ALTERSKATEGORIE_GROB | -0.2066 |
| LP_STATUS_GROB | -0.2118 |
| FINANZ_MINIMALIST | -0.2446 |
comp = 2
result = pca_weights(df_impute, pca_40, comp)
result.head()
| D2 | |
|---|---|
| SEMIO_ERL | 0.1916 |
| FINANZ_HAUSBAUER | 0.1854 |
| ALTERSKATEGORIE_GROB | 0.1835 |
| CAMEO_DEUG_2015 | 0.1631 |
| FINANZ_VORSORGER | 0.1592 |
Positive weights
Negative weights
result.tail()
| D2 | |
|---|---|
| FINANZ_UNAUFFAELLIGER | -0.1771 |
| MOBI_REGIO | -0.1781 |
| ONLINE_AFFINITAET | -0.1818 |
| SEMIO_KULT | -0.1834 |
| SEMIO_REL | -0.1912 |
comp = 3
result = pca_weights(df_impute, pca_40, comp)
result.head()
| D3 | |
|---|---|
| SEMIO_VERT | 0.3269 |
| SEMIO_SOZ | 0.2571 |
| SEMIO_FAM | 0.2496 |
| SEMIO_KULT | 0.2350 |
| FINANZ_MINIMALIST | 0.1261 |
Positive weights
Negative weights
result.tail()
| D3 | |
|---|---|
| SEMIO_RAT | -0.2052 |
| SEMIO_KRIT | -0.2641 |
| SEMIO_DOM | -0.3036 |
| SEMIO_KAEM | -0.3220 |
| ANREDE_KZ | -0.3572 |
The first component depends on the personality and financial characteristics. It captures positively money-saver (FINANZ_SPARER), dutiful (SEMIO_PFLICHT) and religious (SEMIO_REL) people. It also depends on household net income (HH_EINKOMMEN_SCORE) and the year of dominating movement of person's youth (DACADE). Conversely, there are negative weights associated with financially be prepared (FINANZ_VORSORGER), low financial interest (FINANZ_MINIMALIST), movement patterns (MOBI_REGIO), age (ALTERSKATEGORIE_GROB), and socal status (LP_STATUS_GROB).
For the second component, we have positive weight associated with age (ALTERSKATEGORIE_GROB), event-oriented (SEMIO_ERL), and financial characteristics - home ownership (FINANZ_HAUSBAUER) and be prepared (FINANZ_VORSORGER), and wealth / life stage (CAMEO_DEUG_2015). On the other hand, we have negative weight associated with inconspicuous financial characteristics (FINANA_UNAUFFAELLIGER), culuter-minded (SEMIO_KULT), and religious (SEMIO_REL) personalities and Online affinity (ONLINE_AFFINITAET).
Lastly, the third principal component displays positive weights as several personalities - dreamful (SEMIO_VERT), socially-minded (SEMIO_SOZ), family-minded (SEMIO_FAM), and cultural-minded (SEMIO_KULT) - and low financial interset (FINANZ_MINIMALIST). Conversely, we have negative weights associated with opposite personalities against the positive weights such as rational (SEMIO_RAT), critical-minded (SEMIO_KRIT), dominant-minded (SEMIO_DOM), and combative attitude (SEMIO_KAEM).
You've assessed and cleaned the demographics data, then scaled and transformed them. Now, it's time to see how the data clusters in the principal components space. In this substep, you will apply k-means clustering to the dataset and use the average within-cluster distances from each point to their assigned cluster's centroid to decide on a number of clusters to keep.
.score() method might be useful here, but note that in sklearn, scores tend to be defined so that larger is better. Try applying it to a small, toy dataset, or use an internet search to help your understanding.# Over a number of different cluster counts...
# run k-means clustering on the data and...
# compute the average within-cluster distances.
from sklearn.cluster import KMeans
def kmeans_score(data, center):
"""Function to get kmeans' score"""
kmeans = KMeans(n_clusters=center)
model = kmeans.fit(data)
score = np.abs(model.score(data))
return score
# Investigate the change in within-cluster distance across number of clusters.
# HINT: Use matplotlib's plot function to visualize this relationship.
scores = []
centers = list(range(3, 30, 4))
for center in centers:
scores.append(kmeans_score(X_pca, center))
plt.plot(centers, scores, linestyle='--', marker='o', color='b');
plt.xlabel('K');
plt.ylabel('SSE');
plt.title('SSE vs. K');
# Re-fit the k-means model with the selected number of clusters and obtain
# cluster predictions for the general population demographics data.
kmeans = KMeans(n_clusters=7)
model_7 = kmeans.fit(X_pca_40)
azdias_pred = model_7.predict(X_pca_40)
I decided to choose 7 clusters, because the plot shows that the SSE score drops significantly till k=7, then starts to flatten out.
Now that you have clusters and cluster centers for the general population, it's time to see how the customer data maps on to those clusters. Take care to not confuse this for re-fitting all of the models to the customer data. Instead, you're going to use the fits from the general population to clean, transform, and cluster the customer data. In the last step of the project, you will interpret how the general population fits apply to the customer data.
;) delimited.clean_data() function you created earlier. (You can assume that the customer demographics data has similar meaning behind missing data patterns as the general demographics data.).fit() or .fit_transform() method to re-fit the old objects, nor should you be creating new sklearn objects! Carry the data through the feature scaling, PCA, and clustering steps, obtaining cluster assignments for all of the data in the customer demographics data.import os
os.getcwd()
'/Users/yejiseoung/Dropbox/My Mac (Yejis-MacBook-Pro.local)/Documents/Projects/UdacityClusterProject'
# Load in the customer demographics data path.
d_path = Path('/Users/yejiseoung/Dropbox/My Mac (Yejis-MacBook-Pro.local)/Documents/Projects/UdacityClusterProject/Data')
df, feat_info = clean_data(d_path)
Original dataset shape: (891221, 85) I will drop columns because they have more than 30% of missing values in columns: ['AGER_TYP', 'GEBURTSJAHR', 'TITEL_KZ', 'ALTER_HH', 'KK_KUNDENTYP', 'KBA05_BAUMAX'] Dataset after dropped columns which have more than 30% of missing values: (891221, 79) Dataset after dropped rows which have more than 30% of missing values: (798067, 79) Dropped 17 redundant columns Final dataset's shape: (798067, 66)
def get_dtypes(feat_info):
""" Create lists for features' dtypes"""
num_feats, cat_feats, mix_feats = [], [], []
for i in range(feat_info.shape[0]):
if feat_info['type'][i] == 'ordinal':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'numeric':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'interval':
num_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'categorical':
cat_feats.append(feat_info['attribute'][i])
elif feat_info['type'][i] == 'mixed':
mix_feats.append(feat_info['attribute'][i])
print("The number of numerical features: {}, \nThe number of categorical features: {}, \nThe number of mixed features: {}".format(len(num_feats), len(cat_feats), len(mix_feats)))
return num_feats, cat_feats, mix_feats
num_feats, cat_feats, mix_feats = get_dtypes(feat_info)
The number of numerical features: 57, The number of categorical features: 21, The number of mixed features: 7
def create_feature_lists(df, num_feats, cat_feats, mix_feats):
"""Create feature lists that we need to impute missing NaN"""
copy = df.copy()
# create column lists that we need to deal with for imputing NaN
copy.drop(copy.columns[copy.apply(lambda col: col.isnull().sum() == 0)], axis=1, inplace=True)
nan_lists = list(copy.columns)
# Create column lists that are numerical, categorical that have NaN values
nan_num_list = list(set(num_feats).intersection(set(nan_lists)))
nan_cat_list = list(set(cat_feats).intersection(set(nan_lists)))
# for mix features, we have 4 columns, so append these to cat_lists
nan_cat_list.append('PLZ8_BAUMAX')
nan_cat_list.append('DACADE')
nan_cat_list.append('WEALTH')
nan_cat_list.append('LIFE_STAGE')
return nan_num_list, nan_cat_list
nan_num_list, nan_cat_list = create_feature_lists(df, num_feats, cat_feats, mix_feats)
def impute_data(df, nan_num_list, nan_cat_list):
""" Function to impute missing values
For numerical variables, we will fill median with NaN.
For categorical and mix variables, we will fill mode with NaN."""
# Create new dataframe by copying original dataset
df_impute = df.copy()
for num in nan_num_list:
df_impute[num] = df_impute[num].fillna(df_impute[num].median())
for cat in nan_cat_list:
df_impute[cat] = df_impute[cat].astype('category')
df_impute[cat] = df_impute[cat].fillna(df_impute[cat].value_counts().index[0])
return df_impute
df_impute = impute_data(df, nan_num_list, nan_cat_list)
df_impute.head()
| ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | CAMEO_DEUG_2015 | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DACADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | 1.0 | 2.0 | 5.0 | 1.0 | 5.0 | 2.0 | 5.0 | 4.0 | 5.0 | 1.0 | 10.0 | 0 | 3.0 | 3.0 | 1.0 | 1.0 | 1.0 | 5.0 | 4.0 | 4.0 | 3.0 | 1.0 | 2.0 | 2.0 | 3.0 | 6.0 | 4.0 | 7.0 | 4.0 | 7.0 | 6.0 | 3.0 | 1.0 | 2.0 | 5.0 | 2.0 | 0.0 | 6.0 | 3.0 | 9.0 | 11.0 | 0.0 | 1.0 | 1992.0 | 2 | 8 | 1.0 | 6.0 | 3.0 | 8.0 | 3.0 | 2.0 | 1.0 | 3.0 | 3.0 | 963.0 | 1.0 | 5.0 | 4.0 | 3.0 | 5.0 | 4.0 | 0 | 1990.0 | 1.0 | 1.0 |
| 2 | 3.0 | 2.0 | 3.0 | 1.0 | 4.0 | 1.0 | 2.0 | 3.0 | 5.0 | 1.0 | 10.0 | 1 | 3.0 | 1.0 | 2.0 | 1.0 | 3.0 | 4.0 | 1.0 | 3.0 | 3.0 | 4.0 | 4.0 | 6.0 | 3.0 | 4.0 | 7.0 | 7.0 | 7.0 | 3.0 | 3.0 | 2.0 | 0.0 | 1.0 | 5.0 | 1.0 | 0.0 | 4.0 | 3.0 | 9.0 | 10.0 | 0.0 | 5.0 | 1992.0 | 2 | 4 | 3.0 | 2.0 | 4.0 | 4.0 | 4.0 | 2.0 | 3.0 | 2.0 | 2.0 | 712.0 | 1.0 | 4.0 | 4.0 | 3.0 | 5.0 | 2.0 | 1 | 1990.0 | 4.0 | 4.0 |
| 3 | 4.0 | 2.0 | 2.0 | 4.0 | 2.0 | 5.0 | 2.0 | 1.0 | 2.0 | 6.0 | 1.0 | 0 | 2.0 | 1.0 | 4.0 | 1.0 | 2.0 | 5.0 | 1.0 | 2.0 | 1.0 | 4.0 | 4.0 | 7.0 | 4.0 | 3.0 | 4.0 | 4.0 | 5.0 | 4.0 | 4.0 | 1.0 | 0.0 | 1.0 | 3.0 | 0.0 | 0.0 | 1.0 | 4.0 | 9.0 | 1.0 | 0.0 | 4.0 | 1997.0 | 2 | 2 | 4.0 | 4.0 | 2.0 | 6.0 | 4.0 | 3.0 | 4.0 | 1.0 | 5.0 | 596.0 | 1.0 | 3.0 | 4.0 | 2.0 | 3.0 | 3.0 | 0 | 1970.0 | 5.0 | 2.0 |
| 4 | 3.0 | 1.0 | 5.0 | 4.0 | 3.0 | 4.0 | 1.0 | 3.0 | 2.0 | 5.0 | 5.0 | 0 | 3.0 | 5.0 | 2.0 | 1.0 | 5.0 | 6.0 | 4.0 | 4.0 | 2.0 | 7.0 | 4.0 | 4.0 | 6.0 | 2.0 | 3.0 | 2.0 | 2.0 | 4.0 | 2.0 | 2.0 | 0.0 | 2.0 | 4.0 | 4.0 | 0.0 | 5.0 | 2.0 | 9.0 | 3.0 | 0.0 | 4.0 | 1992.0 | 2 | 6 | 3.0 | 2.0 | 5.0 | 1.0 | 5.0 | 3.0 | 3.0 | 5.0 | 5.0 | 435.0 | 2.0 | 3.0 | 3.0 | 4.0 | 6.0 | 5.0 | 0 | 1970.0 | 2.0 | 3.0 |
| 5 | 1.0 | 2.0 | 2.0 | 3.0 | 1.0 | 5.0 | 2.0 | 2.0 | 5.0 | 2.0 | 1.0 | 0 | 3.0 | 1.0 | 2.0 | 1.0 | 3.0 | 2.0 | 4.0 | 7.0 | 4.0 | 2.0 | 2.0 | 2.0 | 5.0 | 7.0 | 4.0 | 4.0 | 4.0 | 7.0 | 6.0 | 0.0 | 0.0 | 2.0 | 4.0 | 1.0 | 0.0 | 5.0 | 6.0 | 9.0 | 5.0 | 0.0 | 5.0 | 1992.0 | 2 | 8 | 4.0 | 6.0 | 2.0 | 7.0 | 4.0 | 4.0 | 4.0 | 1.0 | 5.0 | 1300.0 | 1.0 | 5.0 | 5.0 | 2.0 | 3.0 | 3.0 | 0 | 1950.0 | 1.0 | 4.0 |
col_names = df_impute.columns
scaler = StandardScaler()
df_impute = scaler.fit_transform(df_impute)
df_impute = pd.DataFrame(df_impute, columns = col_names)
df_impute.head()
| ALTERSKATEGORIE_GROB | ANREDE_KZ | CJT_GESAMTTYP | FINANZ_MINIMALIST | FINANZ_SPARER | FINANZ_VORSORGER | FINANZ_ANLEGER | FINANZ_UNAUFFAELLIGER | FINANZ_HAUSBAUER | FINANZTYP | GFK_URLAUBERTYP | GREEN_AVANTGARDE | HEALTH_TYP | LP_FAMILIE_GROB | LP_STATUS_GROB | NATIONALITAET_KZ | RETOURTYP_BK_S | SEMIO_SOZ | SEMIO_FAM | SEMIO_REL | SEMIO_MAT | SEMIO_VERT | SEMIO_LUST | SEMIO_ERL | SEMIO_KULT | SEMIO_RAT | SEMIO_KRIT | SEMIO_DOM | SEMIO_KAEM | SEMIO_PFLICHT | SEMIO_TRADV | SHOPPER_TYP | SOHO_KZ | VERS_TYP | ZABEOTYP | ANZ_PERSONEN | ANZ_TITEL | HH_EINKOMMEN_SCORE | W_KEIT_KIND_HH | WOHNDAUER_2008 | ANZ_HAUSHALTE_AKTIV | ANZ_HH_TITEL | KONSUMNAEHE | MIN_GEBAEUDEJAHR | OST_WEST_KZ | CAMEO_DEUG_2015 | KBA05_GBZ | BALLRAUM | EWDICHTE | INNENSTADT | GEBAEUDETYP_RASTER | KKK | MOBI_REGIO | ONLINE_AFFINITAET | REGIOTYP | KBA13_ANZAHL_PKW | PLZ8_BAUMAX | PLZ8_HHZ | PLZ8_GBZ | ARBEIT | ORTSGR_KLS9 | RELAT_AB | MAINSTREAM_AVANTGARDE | DACADE | WEALTH | LIFE_STAGE | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | -1.766647 | 0.957912 | 0.974332 | -1.494594 | 1.537920 | -1.040686 | 1.465965 | 0.958633 | 1.339319 | -1.342038 | 0.698526 | -0.530407 | 1.096615 | 0.401372 | -0.960530 | -0.346454 | -1.686349 | 0.443205 | -0.059355 | 0.002834 | -0.463909 | -1.684507 | -1.109913 | -1.435372 | -0.578164 | 1.274185 | -0.312196 | 1.339262 | -0.157565 | 1.518699 | 1.288987 | 1.434333 | 10.85417 | 0.922940 | 1.151759 | 0.234458 | -0.060408 | 1.026720 | -0.671568 | 0.567332 | 0.171649 | -0.125133 | -1.304750 | -0.383167 | 0.517425 | 0.981383 | -1.659274 | 0.845768 | -0.546589 | 1.701105 | -0.799742 | -0.791629 | -1.411422 | 0.171117 | -0.857885 | 1.020668 | -0.63327 | 1.430458 | 0.574309 | -0.166387 | -0.127042 | 0.684885 | -0.585967 | 1.098064 | -1.175655 | -1.248888 |
| 1 | 0.200522 | 0.957912 | -0.329868 | -1.494594 | 0.864560 | -1.766972 | -0.570999 | 0.244109 | 1.339319 | -1.342038 | 0.698526 | 1.885345 | 1.096615 | -0.784149 | -0.298869 | -0.346454 | -0.307722 | -0.072013 | -1.626994 | -0.520587 | -0.463909 | -0.142554 | -0.158741 | 0.754262 | -0.578164 | 0.064233 | 1.391992 | 1.339262 | 1.448745 | -0.638942 | -0.410210 | 0.443769 | -0.09213 | -1.083494 | 1.151759 | -0.630198 | -0.060408 | -0.267573 | -0.671568 | 0.567332 | 0.107608 | -0.125133 | 1.274826 | -0.383167 | 0.517425 | -0.625339 | -0.116192 | -0.986554 | 0.035364 | -0.271086 | 0.283466 | -0.791629 | 0.024866 | -0.473542 | -1.424136 | 0.276843 | -0.63327 | 0.390764 | 0.574309 | -0.166387 | -0.127042 | -0.789025 | 1.706581 | 1.098064 | 0.869682 | 0.767097 |
| 2 | 1.184107 | 0.957912 | -0.981968 | 0.683145 | -0.482159 | 1.138172 | -0.570999 | -1.184938 | -0.791197 | 1.056389 | -1.814355 | -0.530407 | -0.256992 | -0.784149 | 1.024455 | -0.346454 | -0.997036 | 0.443205 | -1.626994 | -1.044008 | -1.509281 | -0.142554 | -0.158741 | 1.301671 | -0.067376 | -0.540743 | -0.312196 | -0.303542 | 0.377872 | -0.099532 | 0.156189 | -0.546795 | -0.09213 | -1.083494 | -0.268923 | -1.494855 | -0.060408 | -2.209012 | -0.087450 | 0.567332 | -0.468759 | -0.125133 | 0.629932 | 1.117198 | 0.517425 | -1.428699 | 0.655349 | -0.070393 | -1.128543 | 0.715010 | 0.283466 | 0.269703 | 0.743009 | -1.118201 | 0.274619 | -0.066917 | -0.63327 | -0.648929 | 0.574309 | -1.169906 | -0.997550 | -0.052070 | -0.585967 | -0.267784 | 1.551461 | -0.576893 |
| 3 | 0.200522 | -1.043937 | 0.974332 | 0.683145 | 0.191200 | 0.411886 | -1.249987 | 0.244109 | -0.791197 | 0.576704 | -0.697519 | -0.530407 | 1.096615 | 1.586893 | -0.298869 | -0.346454 | 1.070905 | 0.958423 | -0.059355 | 0.002834 | -0.986595 | 1.399399 | -0.158741 | -0.340555 | 0.954200 | -1.145720 | -0.880259 | -1.398745 | -1.228438 | -0.099532 | -0.976609 | 0.443769 | -0.09213 | 0.922940 | 0.441418 | 1.963772 | -0.060408 | 0.379574 | -1.255686 | 0.567332 | -0.340677 | -0.125133 | 0.629932 | -0.383167 | 0.517425 | 0.178022 | -0.116192 | -0.986554 | 0.617318 | -1.750229 | 1.366673 | 0.269703 | 0.024866 | 1.460434 | 0.274619 | -0.544032 | 0.05786 | -0.648929 | -0.337194 | 0.837133 | 0.308212 | 1.421840 | -0.585967 | -0.267784 | -0.493876 | 0.095102 |
| 4 | -1.766647 | 0.957912 | -0.981968 | -0.042768 | -1.155519 | 1.138172 | -0.570999 | -0.470414 | 1.339319 | -0.862353 | -1.814355 | -0.530407 | 1.096615 | -0.784149 | -0.298869 | -0.346454 | -0.307722 | -1.102449 | -0.059355 | 1.573097 | 0.058776 | -1.170522 | -1.109913 | -1.435372 | 0.443412 | 1.879161 | -0.312196 | -0.303542 | -0.157565 | 1.518699 | 1.288987 | -1.537359 | -0.09213 | 0.922940 | 0.441418 | -0.630198 | -0.060408 | 0.379574 | 1.080786 | 0.567332 | -0.212596 | -0.125133 | 1.274826 | -0.383167 | 0.517425 | 0.981383 | 0.655349 | 0.845768 | -1.128543 | 1.208058 | 0.283466 | 1.331035 | 0.743009 | -1.118201 | 0.274619 | 2.019350 | -0.63327 | 1.430458 | 1.485812 | -1.169906 | -0.997550 | -0.052070 | -0.585967 | -1.633632 | -1.175655 | 0.767097 |
df_impute.shape
(798067, 66)
# Apply preprocessing, feature transformation, and clustering from the general
# demographics onto the customer data, obtaining cluster predictions for the
# customer demographics data.
# set up the data path to load data
d_path = Path('/Users/yejiseoung/Dropbox/My Mac (Yejis-MacBook-Pro.local)/Documents/Projects/UdacityClusterProject/Data')
# load data
df, feat_info = clean_data(d_path)
# create lists of features depending on dtypes
num_feats, cat_feats, mix_feats = get_dtypes(feat_info)
# create lists of features with missing values for impute data
nan_num_list, nan_cat_list = create_feature_lists(df, num_feats, cat_feats, mix_feats)
# create new dataframe that impute missing values
df_impute = impute_data(df, nan_num_list, nan_cat_list)
# Apply scaler
col_names = df_impute.columns
df_impute = scaler.transform(df_impute)
df_impute = pd.DataFrame(df_impute, columns=col_names)
# obtain the same components for the customers data as the general population data
pca = PCA(n_components=40)
customers_pca = pca.fit_transform(df_impute)
# obtain the distribution of the cusomters in the clusters built for the general population
kmeans = KMeans(n_clusters=7)
model = kmeans.fit(customers_pca)
customers_pred = model.predict(customers_pca)
Original dataset shape: (891221, 85) I will drop columns because they have more than 30% of missing values in columns: ['AGER_TYP', 'GEBURTSJAHR', 'TITEL_KZ', 'ALTER_HH', 'KK_KUNDENTYP', 'KBA05_BAUMAX'] Dataset after dropped columns which have more than 30% of missing values: (891221, 79) Dataset after dropped rows which have more than 30% of missing values: (798067, 79) Dropped 17 redundant columns Final dataset's shape: (798067, 66) The number of numerical features: 57, The number of categorical features: 21, The number of mixed features: 7
At this point, you have clustered data based on demographics of the general population of Germany, and seen how the customer data for a mail-order sales company maps onto those demographic clusters. In this final substep, you will compare the two cluster distributions to see where the strongest customer base for the company is.
Consider the proportion of persons in each cluster for the general population, and the proportions for the customers. If we think the company's customer base to be universal, then the cluster assignment proportions should be fairly similar between the two. If there are only particular segments of the population that are interested in the company's products, then we should see a mismatch from one to the other. If there is a higher proportion of persons in a cluster for the customer data compared to the general population (e.g. 5% of persons are assigned to a cluster for the general population, but 15% of the customer data is closest to that cluster's centroid) then that suggests the people in that cluster to be a target audience for the company. On the other hand, the proportion of the data in a cluster being larger in the general population than the customer data (e.g. only 2% of customers closest to a population centroid that captures 6% of the data) suggests that group of persons to be outside of the target demographics.
Take a look at the following points in this step:
countplot() or barplot() function could be handy..inverse_transform() method of the PCA and StandardScaler objects to transform centroids back to the original data space and interpret the retrieved values directly.# Compare the proportion of data in each cluster for the customer data to the
# proportion of data in each cluster for the general population.
fig, ax = plt.subplots(1,2, figsize=(10,4))
fig.subplots_adjust(hspace=1, wspace=0.3)
sns.countplot(customers_pred, ax=ax[0])
ax[0].set_title('Customer Clusters')
sns.countplot(azdias_pred, ax=ax[1])
ax[1].set_title('General Clusters');
# What kinds of people are part of a cluster that is overrepresented in the
# customer data compared to the general population?
centroid_3 = scaler.inverse_transform(pca_40.inverse_transform(model_7.cluster_centers_[3]))
overrepresented_c = pd.Series(data=centroid_3, index=df_impute.columns)
overrepresented_c
ALTERSKATEGORIE_GROB 1.753695 ANREDE_KZ 1.971262 CJT_GESAMTTYP 4.132384 FINANZ_MINIMALIST 1.216146 FINANZ_SPARER 4.274029 FINANZ_VORSORGER 2.180830 FINANZ_ANLEGER 4.060896 FINANZ_UNAUFFAELLIGER 3.821095 FINANZ_HAUSBAUER 4.180104 FINANZTYP 1.962080 GFK_URLAUBERTYP 8.784850 GREEN_AVANTGARDE 0.059927 HEALTH_TYP 2.178185 LP_FAMILIE_GROB 1.965777 LP_STATUS_GROB 1.066275 NATIONALITAET_KZ 1.338331 RETOURTYP_BK_S 2.727570 SEMIO_SOZ 3.236103 SEMIO_FAM 4.017306 SEMIO_REL 5.397509 SEMIO_MAT 4.761847 SEMIO_VERT 2.351609 SEMIO_LUST 3.388240 SEMIO_ERL 4.362703 SEMIO_KULT 4.167569 SEMIO_RAT 6.010063 SEMIO_KRIT 5.452259 SEMIO_DOM 6.028540 SEMIO_KAEM 6.032817 SEMIO_PFLICHT 6.134072 SEMIO_TRADV 5.446051 SHOPPER_TYP 1.619916 SOHO_KZ 0.007889 VERS_TYP 1.561075 ZABEOTYP 4.391814 ANZ_PERSONEN 1.431058 ANZ_TITEL 0.002453 HH_EINKOMMEN_SCORE 5.590790 W_KEIT_KIND_HH 3.995225 WOHNDAUER_2008 7.291345 ANZ_HAUSHALTE_AKTIV 15.549208 ANZ_HH_TITEL 0.060174 KONSUMNAEHE 2.089235 MIN_GEBAEUDEJAHR 1992.415820 OST_WEST_KZ 1.739342 CAMEO_DEUG_2015 7.579383 KBA05_GBZ 2.185157 BALLRAUM 3.140159 EWDICHTE 5.220172 INNENSTADT 3.340238 GEBAEUDETYP_RASTER 3.366772 KKK 2.909719 MOBI_REGIO 1.820043 ONLINE_AFFINITAET 2.846766 REGIOTYP 5.049585 KBA13_ANZAHL_PKW 510.732920 PLZ8_BAUMAX 3.061256 PLZ8_HHZ 3.753498 PLZ8_GBZ 2.708342 ARBEIT 3.684879 ORTSGR_KLS9 7.032933 RELAT_AB 3.735867 MAINSTREAM_AVANTGARDE 0.139817 DACADE 1986.775582 WEALTH 1.576860 LIFE_STAGE 1.992632 dtype: float64
# What kinds of people are part of a cluster that is underrepresented in the
# customer data compared to the general population?
centroid_6 = scaler.inverse_transform(pca_40.inverse_transform(model_7.cluster_centers_[6]))
underrepresented_c = pd.Series(data=centroid_6, index=df_impute.columns)
underrepresented_c
ALTERSKATEGORIE_GROB 3.567169 ANREDE_KZ 1.982046 CJT_GESAMTTYP 2.875163 FINANZ_MINIMALIST 2.513971 FINANZ_SPARER 1.881943 FINANZ_VORSORGER 4.354466 FINANZ_ANLEGER 2.305143 FINANZ_UNAUFFAELLIGER 1.651325 FINANZ_HAUSBAUER 4.352242 FINANZTYP 4.309806 GFK_URLAUBERTYP 7.456441 GREEN_AVANTGARDE 0.048262 HEALTH_TYP 1.982893 LP_FAMILIE_GROB 1.745247 LP_STATUS_GROB 1.456976 NATIONALITAET_KZ 1.071056 RETOURTYP_BK_S 4.221050 SEMIO_SOZ 3.226837 SEMIO_FAM 2.176469 SEMIO_REL 2.064910 SEMIO_MAT 2.515923 SEMIO_VERT 2.663746 SEMIO_LUST 5.299602 SEMIO_ERL 6.614528 SEMIO_KULT 1.841236 SEMIO_RAT 3.397352 SEMIO_KRIT 5.853368 SEMIO_DOM 5.824050 SEMIO_KAEM 6.137488 SEMIO_PFLICHT 2.933695 SEMIO_TRADV 2.338742 SHOPPER_TYP 2.048194 SOHO_KZ 0.007502 VERS_TYP 1.633247 ZABEOTYP 3.344223 ANZ_PERSONEN 1.353248 ANZ_TITEL 0.003146 HH_EINKOMMEN_SCORE 5.440234 W_KEIT_KIND_HH 4.813921 WOHNDAUER_2008 8.097534 ANZ_HAUSHALTE_AKTIV 14.556255 ANZ_HH_TITEL 0.094611 KONSUMNAEHE 2.322995 MIN_GEBAEUDEJAHR 1992.612245 OST_WEST_KZ 1.723499 CAMEO_DEUG_2015 7.142921 KBA05_GBZ 2.241542 BALLRAUM 3.520147 EWDICHTE 4.845801 INNENSTADT 3.730667 GEBAEUDETYP_RASTER 3.481670 KKK 2.848043 MOBI_REGIO 1.918818 ONLINE_AFFINITAET 1.660305 REGIOTYP 4.812926 KBA13_ANZAHL_PKW 555.981179 PLZ8_BAUMAX 2.630361 PLZ8_HHZ 3.726805 PLZ8_GBZ 2.909001 ARBEIT 3.567993 ORTSGR_KLS9 6.436034 RELAT_AB 3.628561 MAINSTREAM_AVANTGARDE 0.110579 DACADE 1963.806514 WEALTH 1.752932 LIFE_STAGE 2.677369 dtype: float64
compare = pd.DataFrame([overrepresented_c, underrepresented_c])
compare = compare.T
compare.columns = ['over_cent_3', 'under_cent_6']
compare
| over_cent_3 | under_cent_6 | |
|---|---|---|
| ALTERSKATEGORIE_GROB | 1.753695 | 3.567169 |
| ANREDE_KZ | 1.971262 | 1.982046 |
| CJT_GESAMTTYP | 4.132384 | 2.875163 |
| FINANZ_MINIMALIST | 1.216146 | 2.513971 |
| FINANZ_SPARER | 4.274029 | 1.881943 |
| FINANZ_VORSORGER | 2.180830 | 4.354466 |
| FINANZ_ANLEGER | 4.060896 | 2.305143 |
| FINANZ_UNAUFFAELLIGER | 3.821095 | 1.651325 |
| FINANZ_HAUSBAUER | 4.180104 | 4.352242 |
| FINANZTYP | 1.962080 | 4.309806 |
| GFK_URLAUBERTYP | 8.784850 | 7.456441 |
| GREEN_AVANTGARDE | 0.059927 | 0.048262 |
| HEALTH_TYP | 2.178185 | 1.982893 |
| LP_FAMILIE_GROB | 1.965777 | 1.745247 |
| LP_STATUS_GROB | 1.066275 | 1.456976 |
| NATIONALITAET_KZ | 1.338331 | 1.071056 |
| RETOURTYP_BK_S | 2.727570 | 4.221050 |
| SEMIO_SOZ | 3.236103 | 3.226837 |
| SEMIO_FAM | 4.017306 | 2.176469 |
| SEMIO_REL | 5.397509 | 2.064910 |
| SEMIO_MAT | 4.761847 | 2.515923 |
| SEMIO_VERT | 2.351609 | 2.663746 |
| SEMIO_LUST | 3.388240 | 5.299602 |
| SEMIO_ERL | 4.362703 | 6.614528 |
| SEMIO_KULT | 4.167569 | 1.841236 |
| SEMIO_RAT | 6.010063 | 3.397352 |
| SEMIO_KRIT | 5.452259 | 5.853368 |
| SEMIO_DOM | 6.028540 | 5.824050 |
| SEMIO_KAEM | 6.032817 | 6.137488 |
| SEMIO_PFLICHT | 6.134072 | 2.933695 |
| SEMIO_TRADV | 5.446051 | 2.338742 |
| SHOPPER_TYP | 1.619916 | 2.048194 |
| SOHO_KZ | 0.007889 | 0.007502 |
| VERS_TYP | 1.561075 | 1.633247 |
| ZABEOTYP | 4.391814 | 3.344223 |
| ANZ_PERSONEN | 1.431058 | 1.353248 |
| ANZ_TITEL | 0.002453 | 0.003146 |
| HH_EINKOMMEN_SCORE | 5.590790 | 5.440234 |
| W_KEIT_KIND_HH | 3.995225 | 4.813921 |
| WOHNDAUER_2008 | 7.291345 | 8.097534 |
| ANZ_HAUSHALTE_AKTIV | 15.549208 | 14.556255 |
| ANZ_HH_TITEL | 0.060174 | 0.094611 |
| KONSUMNAEHE | 2.089235 | 2.322995 |
| MIN_GEBAEUDEJAHR | 1992.415820 | 1992.612245 |
| OST_WEST_KZ | 1.739342 | 1.723499 |
| CAMEO_DEUG_2015 | 7.579383 | 7.142921 |
| KBA05_GBZ | 2.185157 | 2.241542 |
| BALLRAUM | 3.140159 | 3.520147 |
| EWDICHTE | 5.220172 | 4.845801 |
| INNENSTADT | 3.340238 | 3.730667 |
| GEBAEUDETYP_RASTER | 3.366772 | 3.481670 |
| KKK | 2.909719 | 2.848043 |
| MOBI_REGIO | 1.820043 | 1.918818 |
| ONLINE_AFFINITAET | 2.846766 | 1.660305 |
| REGIOTYP | 5.049585 | 4.812926 |
| KBA13_ANZAHL_PKW | 510.732920 | 555.981179 |
| PLZ8_BAUMAX | 3.061256 | 2.630361 |
| PLZ8_HHZ | 3.753498 | 3.726805 |
| PLZ8_GBZ | 2.708342 | 2.909001 |
| ARBEIT | 3.684879 | 3.567993 |
| ORTSGR_KLS9 | 7.032933 | 6.436034 |
| RELAT_AB | 3.735867 | 3.628561 |
| MAINSTREAM_AVANTGARDE | 0.139817 | 0.110579 |
| DACADE | 1986.775582 | 1963.806514 |
| WEALTH | 1.576860 | 1.752932 |
| LIFE_STAGE | 1.992632 | 2.677369 |
Cluster 3 is overrepresented in the customers data compared to general population data. We can see some characteristics of group of population that are relative popular with the mail-order company:
Cluster 6 is underrepresented in the customers data compared to general population data. We can see some characteristics of group of population that are relatively unpopular with the company:
Congratulations on making it this far in the project! Before you finish, make sure to check through the entire notebook from top to bottom to make sure that your analysis follows a logical flow and all of your findings are documented in Discussion cells. Once you've checked over all of your work, you should export the notebook as an HTML document to submit for evaluation. You can do this from the menu, navigating to File -> Download as -> HTML (.html). You will submit both that document and this notebook for your project submission.